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