blob: 2d3afc9fe2f1b11441f5086e268146d839690ba7 [file] [log] [blame]
/*
* 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));
}
}
}