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