SampleMediaRouteProvider.java revision 55e47d370890d3cbdab82857090c42df734ba276
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 com.example.android.supportv7.media;
18
19import com.example.android.supportv7.R;
20
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.IntentFilter.MalformedMimeTypeException;
25import android.content.res.Resources;
26import android.media.MediaRouter;
27import android.net.Uri;
28import android.os.Bundle;
29import android.support.v7.media.MediaControlIntent;
30import android.support.v7.media.MediaRouteProvider;
31import android.support.v7.media.MediaRouter.ControlRequestCallback;
32import android.support.v7.media.MediaRouteProviderDescriptor;
33import android.support.v7.media.MediaRouteDescriptor;
34import android.util.Log;
35import android.widget.Toast;
36
37import java.util.ArrayList;
38import java.util.UUID;
39
40/**
41 * Demonstrates how to create a custom media route provider.
42 *
43 * @see SampleMediaRouteProviderService
44 */
45final class SampleMediaRouteProvider extends MediaRouteProvider {
46    private static final String TAG = "SampleMediaRouteProvider";
47
48    private static final String FIXED_VOLUME_ROUTE_ID = "fixed";
49    private static final String VARIABLE_VOLUME_ROUTE_ID = "variable";
50    private static final int VOLUME_MAX = 10;
51
52    /**
53     * A custom media control intent category for special requests that are
54     * supported by this provider's routes.
55     */
56    public static final String CATEGORY_SAMPLE_ROUTE =
57            "com.example.android.supportv7.media.CATEGORY_SAMPLE_ROUTE";
58
59    /**
60     * A custom media control intent action for special requests that are
61     * supported by this provider's routes.
62     * <p>
63     * This particular request is designed to return a bundle of not very
64     * interesting statistics for demonstration purposes.
65     * </p>
66     *
67     * @see #DATA_PLAYBACK_COUNT
68     */
69    public static final String ACTION_GET_STATISTICS =
70            "com.example.android.supportv7.media.ACTION_GET_STATISTICS";
71
72    /**
73     * {@link #ACTION_GET_STATISTICS} result data: Number of times the
74     * playback action was invoked.
75     */
76    public static final String DATA_PLAYBACK_COUNT =
77            "com.example.android.supportv7.media.EXTRA_PLAYBACK_COUNT";
78
79    private static final ArrayList<IntentFilter> CONTROL_FILTERS;
80    static {
81        IntentFilter f1 = new IntentFilter();
82        f1.addCategory(CATEGORY_SAMPLE_ROUTE);
83        f1.addAction(ACTION_GET_STATISTICS);
84
85        IntentFilter f2 = new IntentFilter();
86        f2.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
87        f2.addAction(MediaControlIntent.ACTION_PLAY);
88        f2.addDataScheme("http");
89        f2.addDataScheme("https");
90        addDataTypeUnchecked(f2, "video/*");
91
92        CONTROL_FILTERS = new ArrayList<IntentFilter>();
93        CONTROL_FILTERS.add(f1);
94        CONTROL_FILTERS.add(f2);
95    }
96
97    private static void addDataTypeUnchecked(IntentFilter filter, String type) {
98        try {
99            filter.addDataType(type);
100        } catch (MalformedMimeTypeException ex) {
101            throw new RuntimeException(ex);
102        }
103    }
104
105    private int mVolume = 5;
106    private int mPlaybackCount;
107
108    public SampleMediaRouteProvider(Context context) {
109        super(context);
110
111        publishRoutes();
112    }
113
114    @Override
115    public RouteController onCreateRouteController(String routeId) {
116        return new SampleRouteController(routeId);
117    }
118
119    private void publishRoutes() {
120        Resources r = getContext().getResources();
121
122        MediaRouteDescriptor routeDescriptor1 = new MediaRouteDescriptor.Builder(
123                FIXED_VOLUME_ROUTE_ID,
124                r.getString(R.string.fixed_volume_route_name))
125                .addControlFilters(CONTROL_FILTERS)
126                .setIconResource(R.drawable.media_route_icon)
127                .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
128                .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED)
129                .setVolume(VOLUME_MAX)
130                .build();
131
132        MediaRouteDescriptor routeDescriptor2 = new MediaRouteDescriptor.Builder(
133                VARIABLE_VOLUME_ROUTE_ID,
134                r.getString(R.string.variable_volume_route_name))
135                .addControlFilters(CONTROL_FILTERS)
136                .setIconResource(R.drawable.media_route_icon)
137                .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
138                .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
139                .setVolumeMax(VOLUME_MAX)
140                .setVolume(mVolume)
141                .build();
142
143        MediaRouteProviderDescriptor providerDescriptor =
144                new MediaRouteProviderDescriptor.Builder()
145                .addRoute(routeDescriptor1)
146                .addRoute(routeDescriptor2)
147                .addDiscoverableControlFilters(CONTROL_FILTERS)
148                .build();
149        setDescriptor(providerDescriptor);
150    }
151
152    private String generateStreamId() {
153        return UUID.randomUUID().toString();
154    }
155
156    private final class SampleRouteController extends MediaRouteProvider.RouteController {
157        private final String mRouteId;
158
159        public SampleRouteController(String routeId) {
160            mRouteId = routeId;
161            Log.d(TAG, mRouteId + ": Controller created");
162        }
163
164        @Override
165        public void onRelease() {
166            Log.d(TAG, mRouteId + ": Controller released");
167        }
168
169        @Override
170        public void onSelect() {
171            Log.d(TAG, mRouteId + ": Selected");
172        }
173
174        @Override
175        public void onUnselect() {
176            Log.d(TAG, mRouteId + ": Unselected");
177        }
178
179        @Override
180        public void onSetVolume(int volume) {
181            Log.d(TAG, mRouteId + ": Set volume to " + volume);
182            if (mRouteId.equals(VARIABLE_VOLUME_ROUTE_ID)) {
183                setVolumeInternal(volume);
184            }
185        }
186
187        @Override
188        public void onUpdateVolume(int delta) {
189            Log.d(TAG, mRouteId + ": Update volume by " + delta);
190            if (mRouteId.equals(VARIABLE_VOLUME_ROUTE_ID)) {
191                setVolumeInternal(mVolume + delta);
192            }
193        }
194
195        private void setVolumeInternal(int volume) {
196            if (volume >= 0 && volume <= VOLUME_MAX) {
197                mVolume = volume;
198                Log.d(TAG, mRouteId + ": New volume is " + mVolume);
199                publishRoutes();
200            }
201        }
202
203        @Override
204        public boolean onControlRequest(Intent intent, ControlRequestCallback callback) {
205            Log.d(TAG, mRouteId + ": Received control request " + intent);
206            if (intent.getAction().equals(MediaControlIntent.ACTION_PLAY)
207                    && intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
208                    && intent.getData() != null) {
209                mPlaybackCount +=1;
210
211                Uri uri = intent.getData();
212                int queueBehavior = intent.getIntExtra(
213                        MediaControlIntent.EXTRA_ITEM_QUEUE_BEHAVIOR,
214                        MediaControlIntent.ITEM_QUEUE_BEHAVIOR_PLAY_NOW);
215                int position = intent.getIntExtra(
216                        MediaControlIntent.EXTRA_ITEM_POSITION, 0);
217                Bundle metadata = intent.getBundleExtra(MediaControlIntent.EXTRA_ITEM_METADATA);
218                Bundle headers = intent.getBundleExtra(
219                        MediaControlIntent.EXTRA_ITEM_HTTP_HEADERS);
220                String streamId = generateStreamId();
221
222                Log.d(TAG, mRouteId + ": Received play request, uri=" + uri
223                        + ", queueBehavior=" + queueBehavior
224                        + ", position=" + position
225                        + ", metadata=" + metadata
226                        + ", headers=" + headers);
227                Toast.makeText(getContext(), "Route received play request: uri=" + uri,
228                        Toast.LENGTH_LONG).show();
229                if (callback != null) {
230                    Bundle result = new Bundle();
231                    result.putString(MediaControlIntent.EXTRA_ITEM_ID, streamId);
232                    callback.onResult(ControlRequestCallback.REQUEST_SUCCEEDED, result);
233                }
234                return true;
235            }
236
237            if (intent.getAction().equals(ACTION_GET_STATISTICS)
238                    && intent.hasCategory(CATEGORY_SAMPLE_ROUTE)) {
239                Bundle data = new Bundle();
240                data.putInt(DATA_PLAYBACK_COUNT, mPlaybackCount);
241                if (callback != null) {
242                    callback.onResult(ControlRequestCallback.REQUEST_SUCCEEDED, data);
243                }
244                return true;
245            }
246            return false;
247        }
248    }
249}