TransportPerformer.java revision 8c7c4c0409bd93f66fe39c5a5298a94f832be31e
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.support.v4.media;
18
19import android.os.SystemClock;
20import android.view.KeyEvent;
21
22/**
23 * Class through which you receive information about media transport actions.
24 * These may either come from key events dispatched directly to your UI, or
25 * events sent over a media button event receiver that this class keeps active
26 * while your window is in focus.
27 */
28public abstract class TransportPerformer {
29    public abstract void onStart();
30
31    public abstract void onStop();
32
33    public abstract void onPause();
34
35    public abstract int onGetDuration();
36
37    public abstract int onGetCurrentPosition();
38
39    public abstract void onSeekTo(int pos);
40
41    public abstract boolean onIsPlaying();
42
43    public int onGetBufferPercentage() {
44        return 100;
45    }
46
47    /**
48     * Retrieves the flags for the media transport control buttons that this transport supports.
49     * Result is a combination of the following flags:
50     *      {@link TransportMediator#FLAG_KEY_MEDIA_PREVIOUS},
51     *      {@link TransportMediator#FLAG_KEY_MEDIA_REWIND},
52     *      {@link TransportMediator#FLAG_KEY_MEDIA_PLAY},
53     *      {@link TransportMediator#FLAG_KEY_MEDIA_PLAY_PAUSE},
54     *      {@link TransportMediator#FLAG_KEY_MEDIA_PAUSE},
55     *      {@link TransportMediator#FLAG_KEY_MEDIA_STOP},
56     *      {@link TransportMediator#FLAG_KEY_MEDIA_FAST_FORWARD},
57     *      {@link TransportMediator#FLAG_KEY_MEDIA_NEXT}
58     *
59     * <p>The default implementation returns:
60     *      {@link TransportMediator#FLAG_KEY_MEDIA_PLAY},
61     *      {@link TransportMediator#FLAG_KEY_MEDIA_PLAY_PAUSE},
62     *      {@link TransportMediator#FLAG_KEY_MEDIA_PAUSE}, and
63     *      {@link TransportMediator#FLAG_KEY_MEDIA_STOP}</p>
64     */
65    public int onGetTransportControlFlags() {
66        return TransportMediator.FLAG_KEY_MEDIA_PLAY
67                | TransportMediator.FLAG_KEY_MEDIA_PLAY_PAUSE
68                | TransportMediator.FLAG_KEY_MEDIA_PAUSE
69                | TransportMediator.FLAG_KEY_MEDIA_STOP;
70    }
71
72    /**
73     * Report that a media button has been pressed.  This is like
74     * {@link android.view.KeyEvent.Callback#onKeyDown(int, android.view.KeyEvent)} but
75     * will only deliver media keys.  The default implementation handles these keys:
76     * <ul>
77     *     <li>KEYCODE_MEDIA_PLAY: call {@link #onStart}</li>
78     *     <li>KEYCODE_MEDIA_PAUSE: call {@link #onPause}</li>
79     *     <li>KEYCODE_MEDIA_STOP: call {@link #onStop}</li>
80     *     <li>KEYCODE_MEDIA_PLAY_PAUSE and KEYCODE_HEADSETHOOK: call {@link #onPause}
81     *          if {@link #onIsPlaying()} returns true, otherwise call {@link #onStart}</li>
82     * </ul>
83     * @param keyCode The code of the media key.
84     * @param event The full key event.
85     * @return Indicate whether the key has been consumed.  The default
86     * implementation always returns true.  This only matters for keys
87     * being dispatched here from
88     * {@link TransportMediator#dispatchKeyEvent(android.view.KeyEvent)
89     * TransportController.dispatchKeyEvent}, and determines whether the key
90     * continues on to its default key handling (which for media keys means
91     * being delivered to the current media remote control, which should
92     * be us).
93     */
94    public boolean onMediaButtonDown(int keyCode, KeyEvent event) {
95        switch (keyCode) {
96            case TransportMediator.KEYCODE_MEDIA_PLAY:
97                onStart();
98                return true;
99            case TransportMediator.KEYCODE_MEDIA_PAUSE:
100                onPause();
101                return true;
102            case KeyEvent.KEYCODE_MEDIA_STOP:
103                onStop();
104                return true;
105            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
106            case KeyEvent.KEYCODE_HEADSETHOOK:
107                if (onIsPlaying()) {
108                    onPause();
109                } else {
110                    onStart();
111                }
112        }
113        return true;
114    }
115
116    /**
117     * Report that a media button has been pressed.  This is like
118     * {@link KeyEvent.Callback#onKeyUp(int, android.view.KeyEvent)} but
119     * will only deliver media keys.  The default implementation does nothing.
120     * @param keyCode The code of the media key.
121     * @param event The full key event.
122     * @return Indicate whether the key has been consumed.  The default
123     * implementation always returns true.  This only matters for keys
124     * being dispatched here from
125     * {@link TransportMediator#dispatchKeyEvent(android.view.KeyEvent)
126     * TransportController.dispatchKeyEvent}, and determines whether the key
127     * continues on to its default key handling (which for media keys means
128     * being delivered to the current media remote control, which should
129     * be us).
130     */
131    public boolean onMediaButtonUp(int keyCode, KeyEvent event) {
132        return true;
133    }
134
135    // Copy constants from framework since we can't link to them.
136    static final int AUDIOFOCUS_GAIN = 1;
137    static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
138    static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
139    static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
140    static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
141    static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
142            -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
143
144    /**
145     * Report that audio focus has changed on the app.  This only happens if
146     * you have indicated you have started playing with
147     * {@link TransportMediator#startPlaying TransportController.startPlaying},
148     * which takes audio focus for you.
149     * @param focusChange The type of focus change, as per
150     * {@link android.media.AudioManager.OnAudioFocusChangeListener#onAudioFocusChange(int)
151     * OnAudioFocusChangeListener.onAudioFocusChange}.  The default implementation will
152     * deliver a {@link KeyEvent#KEYCODE_MEDIA_STOP}
153     * when receiving {@link android.media.AudioManager#AUDIOFOCUS_LOSS}.
154     */
155    public void onAudioFocusChange(int focusChange) {
156        int keyCode = 0;
157        switch (focusChange) {
158            case AUDIOFOCUS_LOSS:
159                // This will cause us to stop playback, which means we drop audio focus
160                // so we will not get any further audio focus gain.
161                keyCode = TransportMediator.KEYCODE_MEDIA_PAUSE;
162                break;
163        }
164        if (keyCode != 0) {
165            final long now = SystemClock.uptimeMillis();
166            onMediaButtonDown(keyCode, new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0));
167            onMediaButtonUp(keyCode, new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0));
168        }
169    }
170}
171