SampleMediaRouteProvider.java revision 57456222f52fbfc1dcfb1b99030aad6acc02ad23
1ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown/*
2ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown * Copyright (C) 2013 The Android Open Source Project
3ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown *
4ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown * you may not use this file except in compliance with the License.
6ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown * You may obtain a copy of the License at
7ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown *
8ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown *
10ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown * Unless required by applicable law or agreed to in writing, software
11ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown * See the License for the specific language governing permissions and
14ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown * limitations under the License.
15ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown */
16ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
17ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownpackage com.example.android.supportv7.media;
18ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
19ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownimport com.example.android.supportv7.R;
20ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
21ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownimport android.content.Context;
22ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownimport android.content.Intent;
23ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownimport android.content.IntentFilter;
24ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownimport android.content.IntentFilter.MalformedMimeTypeException;
25ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownimport android.content.res.Resources;
26ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownimport android.media.MediaRouter;
27ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownimport android.net.Uri;
28ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownimport android.os.Bundle;
2957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.app.PendingIntent;
30ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownimport android.support.v7.media.MediaControlIntent;
31fcb6a9d1caaf43ae41f859ebb58a4483b12475a1Jeff Brownimport android.support.v7.media.MediaItemStatus;
32ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownimport android.support.v7.media.MediaRouteProvider;
33ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownimport android.support.v7.media.MediaRouter.ControlRequestCallback;
3455e47d370890d3cbdab82857090c42df734ba276Jeff Brownimport android.support.v7.media.MediaRouteProviderDescriptor;
3555e47d370890d3cbdab82857090c42df734ba276Jeff Brownimport android.support.v7.media.MediaRouteDescriptor;
36ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownimport android.util.Log;
37ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownimport android.widget.Toast;
3857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.view.Gravity;
3955e47d370890d3cbdab82857090c42df734ba276Jeff Brownimport java.util.ArrayList;
40bc89096eeed02fd163eaed46b88364486c76c4feJeff Brown
41ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown/**
42ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown * Demonstrates how to create a custom media route provider.
43ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown *
44ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown * @see SampleMediaRouteProviderService
45ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown */
46ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brownfinal class SampleMediaRouteProvider extends MediaRouteProvider {
47ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    private static final String TAG = "SampleMediaRouteProvider";
48ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
49ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    private static final String FIXED_VOLUME_ROUTE_ID = "fixed";
50ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    private static final String VARIABLE_VOLUME_ROUTE_ID = "variable";
51ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    private static final int VOLUME_MAX = 10;
52ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
53ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    /**
54ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown     * A custom media control intent category for special requests that are
55ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown     * supported by this provider's routes.
56ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown     */
57ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    public static final String CATEGORY_SAMPLE_ROUTE =
5855e47d370890d3cbdab82857090c42df734ba276Jeff Brown            "com.example.android.supportv7.media.CATEGORY_SAMPLE_ROUTE";
59ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
60ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    /**
61ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown     * A custom media control intent action for special requests that are
62ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown     * supported by this provider's routes.
63ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown     * <p>
64ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown     * This particular request is designed to return a bundle of not very
65ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown     * interesting statistics for demonstration purposes.
66ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown     * </p>
67ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown     *
68ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown     * @see #DATA_PLAYBACK_COUNT
69ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown     */
70ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    public static final String ACTION_GET_STATISTICS =
7155e47d370890d3cbdab82857090c42df734ba276Jeff Brown            "com.example.android.supportv7.media.ACTION_GET_STATISTICS";
72ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
73ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    /**
74ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown     * {@link #ACTION_GET_STATISTICS} result data: Number of times the
75ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown     * playback action was invoked.
76ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown     */
77ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    public static final String DATA_PLAYBACK_COUNT =
7855e47d370890d3cbdab82857090c42df734ba276Jeff Brown            "com.example.android.supportv7.media.EXTRA_PLAYBACK_COUNT";
79ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
8057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang    /*
8157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang     * Set ENABLE_QUEUEING to true to test queuing on MRP. This will make
8257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang     * MRP expose the following two experimental hidden APIs:
8357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang     *     ACTION_ENQUEUE
8457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang     *     ACTION_REMOVE
8557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang     */
8657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang    public static final boolean ENABLE_QUEUEING = false;
8757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
8855e47d370890d3cbdab82857090c42df734ba276Jeff Brown    private static final ArrayList<IntentFilter> CONTROL_FILTERS;
89ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    static {
9055e47d370890d3cbdab82857090c42df734ba276Jeff Brown        IntentFilter f1 = new IntentFilter();
9155e47d370890d3cbdab82857090c42df734ba276Jeff Brown        f1.addCategory(CATEGORY_SAMPLE_ROUTE);
9255e47d370890d3cbdab82857090c42df734ba276Jeff Brown        f1.addAction(ACTION_GET_STATISTICS);
9355e47d370890d3cbdab82857090c42df734ba276Jeff Brown
9455e47d370890d3cbdab82857090c42df734ba276Jeff Brown        IntentFilter f2 = new IntentFilter();
9555e47d370890d3cbdab82857090c42df734ba276Jeff Brown        f2.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
9655e47d370890d3cbdab82857090c42df734ba276Jeff Brown        f2.addAction(MediaControlIntent.ACTION_PLAY);
9755e47d370890d3cbdab82857090c42df734ba276Jeff Brown        f2.addDataScheme("http");
9855e47d370890d3cbdab82857090c42df734ba276Jeff Brown        f2.addDataScheme("https");
9957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f2.addDataScheme("rtsp");
10057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f2.addDataScheme("file");
10155e47d370890d3cbdab82857090c42df734ba276Jeff Brown        addDataTypeUnchecked(f2, "video/*");
10255e47d370890d3cbdab82857090c42df734ba276Jeff Brown
10357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        IntentFilter f3 = new IntentFilter();
10457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f3.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
10557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f3.addAction(MediaControlIntent.ACTION_SEEK);
10657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f3.addAction(MediaControlIntent.ACTION_GET_STATUS);
10757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f3.addAction(MediaControlIntent.ACTION_PAUSE);
10857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f3.addAction(MediaControlIntent.ACTION_RESUME);
10957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f3.addAction(MediaControlIntent.ACTION_STOP);
11057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
11157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        IntentFilter f4 = new IntentFilter();
11257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f4.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
11357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f4.addAction(MediaControlIntent.ACTION_ENQUEUE);
11457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f4.addDataScheme("http");
11557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f4.addDataScheme("https");
11657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f4.addDataScheme("rtsp");
11757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f4.addDataScheme("file");
11857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        addDataTypeUnchecked(f4, "video/*");
11957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
12057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        IntentFilter f5 = new IntentFilter();
12157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f5.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
12257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        f5.addAction(MediaControlIntent.ACTION_REMOVE);
12357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
12455e47d370890d3cbdab82857090c42df734ba276Jeff Brown        CONTROL_FILTERS = new ArrayList<IntentFilter>();
12555e47d370890d3cbdab82857090c42df734ba276Jeff Brown        CONTROL_FILTERS.add(f1);
12655e47d370890d3cbdab82857090c42df734ba276Jeff Brown        CONTROL_FILTERS.add(f2);
12757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        CONTROL_FILTERS.add(f3);
12857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        if (ENABLE_QUEUEING) {
12957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            CONTROL_FILTERS.add(f4);
13057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            CONTROL_FILTERS.add(f5);
13157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        }
132ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    }
133ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
134ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    private static void addDataTypeUnchecked(IntentFilter filter, String type) {
135ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        try {
136ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            filter.addDataType(type);
137ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        } catch (MalformedMimeTypeException ex) {
138ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            throw new RuntimeException(ex);
139ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        }
140ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    }
141ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
142ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    private int mVolume = 5;
14357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang    private int mEnqueueCount;
144ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
145ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    public SampleMediaRouteProvider(Context context) {
146ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        super(context);
147ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
148ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        publishRoutes();
149ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    }
150ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
151ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    @Override
152ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    public RouteController onCreateRouteController(String routeId) {
153ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        return new SampleRouteController(routeId);
154ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    }
155ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
156ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    private void publishRoutes() {
157ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        Resources r = getContext().getResources();
158ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
15955e47d370890d3cbdab82857090c42df734ba276Jeff Brown        MediaRouteDescriptor routeDescriptor1 = new MediaRouteDescriptor.Builder(
160ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown                FIXED_VOLUME_ROUTE_ID,
16155e47d370890d3cbdab82857090c42df734ba276Jeff Brown                r.getString(R.string.fixed_volume_route_name))
162b28eb61b29c0d956a5e504716cdea9f31184a998Jeff Brown                .setDescription(r.getString(R.string.sample_route_description))
16355e47d370890d3cbdab82857090c42df734ba276Jeff Brown                .addControlFilters(CONTROL_FILTERS)
16455e47d370890d3cbdab82857090c42df734ba276Jeff Brown                .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
16555e47d370890d3cbdab82857090c42df734ba276Jeff Brown                .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED)
16655e47d370890d3cbdab82857090c42df734ba276Jeff Brown                .setVolume(VOLUME_MAX)
16755e47d370890d3cbdab82857090c42df734ba276Jeff Brown                .build();
16855e47d370890d3cbdab82857090c42df734ba276Jeff Brown
16955e47d370890d3cbdab82857090c42df734ba276Jeff Brown        MediaRouteDescriptor routeDescriptor2 = new MediaRouteDescriptor.Builder(
170ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown                VARIABLE_VOLUME_ROUTE_ID,
17155e47d370890d3cbdab82857090c42df734ba276Jeff Brown                r.getString(R.string.variable_volume_route_name))
172b28eb61b29c0d956a5e504716cdea9f31184a998Jeff Brown                .setDescription(r.getString(R.string.sample_route_description))
17355e47d370890d3cbdab82857090c42df734ba276Jeff Brown                .addControlFilters(CONTROL_FILTERS)
17455e47d370890d3cbdab82857090c42df734ba276Jeff Brown                .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
17555e47d370890d3cbdab82857090c42df734ba276Jeff Brown                .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
17655e47d370890d3cbdab82857090c42df734ba276Jeff Brown                .setVolumeMax(VOLUME_MAX)
17755e47d370890d3cbdab82857090c42df734ba276Jeff Brown                .setVolume(mVolume)
17855e47d370890d3cbdab82857090c42df734ba276Jeff Brown                .build();
17955e47d370890d3cbdab82857090c42df734ba276Jeff Brown
18055e47d370890d3cbdab82857090c42df734ba276Jeff Brown        MediaRouteProviderDescriptor providerDescriptor =
18155e47d370890d3cbdab82857090c42df734ba276Jeff Brown                new MediaRouteProviderDescriptor.Builder()
18255e47d370890d3cbdab82857090c42df734ba276Jeff Brown                .addRoute(routeDescriptor1)
18355e47d370890d3cbdab82857090c42df734ba276Jeff Brown                .addRoute(routeDescriptor2)
18455e47d370890d3cbdab82857090c42df734ba276Jeff Brown                .build();
185ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        setDescriptor(providerDescriptor);
186ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    }
187ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
18857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang    private void showToast(String msg) {
18957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        Toast toast = Toast.makeText(getContext(),
19057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                "[provider] " + msg, Toast.LENGTH_LONG);
19157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        toast.setGravity(Gravity.TOP, 0, 100);
19257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        toast.show();
193bc89096eeed02fd163eaed46b88364486c76c4feJeff Brown    }
194bc89096eeed02fd163eaed46b88364486c76c4feJeff Brown
195ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    private final class SampleRouteController extends MediaRouteProvider.RouteController {
196ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        private final String mRouteId;
19757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        // Create an overlay display window (used for simulating the remote playback only)
19857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        private final OverlayDisplayWindow mOverlay = new OverlayDisplayWindow(getContext(),
19957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                getContext().getResources().getString(R.string.sample_media_route_provider_remote),
20057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                1024, 768, Gravity.CENTER);
20157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        private final MediaPlayerWrapper mMediaPlayer = new MediaPlayerWrapper(getContext());
20257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        private final MediaSessionManager mSessionManager = new MediaSessionManager();
203ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
204ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        public SampleRouteController(String routeId) {
205ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            mRouteId = routeId;
20657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            mSessionManager.setCallback(mMediaPlayer);
20757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            mOverlay.setOverlayWindowListener(mMediaPlayer);
20857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            mMediaPlayer.setCallback(new MediaPlayerCallback());
209ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            Log.d(TAG, mRouteId + ": Controller created");
210ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        }
211ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
212ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        @Override
213bc89096eeed02fd163eaed46b88364486c76c4feJeff Brown        public void onRelease() {
214ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            Log.d(TAG, mRouteId + ": Controller released");
21557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            mMediaPlayer.release();
216ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        }
217ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
218ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        @Override
219bc89096eeed02fd163eaed46b88364486c76c4feJeff Brown        public void onSelect() {
220ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            Log.d(TAG, mRouteId + ": Selected");
22157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            mOverlay.show();
222ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        }
223ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
224ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        @Override
225bc89096eeed02fd163eaed46b88364486c76c4feJeff Brown        public void onUnselect() {
226ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            Log.d(TAG, mRouteId + ": Unselected");
22757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            mMediaPlayer.onStop();
22857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            mOverlay.dismiss();
229ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        }
230ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
231ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        @Override
232bc89096eeed02fd163eaed46b88364486c76c4feJeff Brown        public void onSetVolume(int volume) {
233ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            Log.d(TAG, mRouteId + ": Set volume to " + volume);
234ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            if (mRouteId.equals(VARIABLE_VOLUME_ROUTE_ID)) {
235ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown                setVolumeInternal(volume);
236ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            }
237ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        }
238ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
239ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        @Override
240bc89096eeed02fd163eaed46b88364486c76c4feJeff Brown        public void onUpdateVolume(int delta) {
241ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            Log.d(TAG, mRouteId + ": Update volume by " + delta);
242ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            if (mRouteId.equals(VARIABLE_VOLUME_ROUTE_ID)) {
243ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown                setVolumeInternal(mVolume + delta);
244ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            }
245ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        }
246ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
247ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        @Override
248bc89096eeed02fd163eaed46b88364486c76c4feJeff Brown        public boolean onControlRequest(Intent intent, ControlRequestCallback callback) {
249ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            Log.d(TAG, mRouteId + ": Received control request " + intent);
25057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            String action = intent.getAction();
25157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
25257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                boolean success = false;
25357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                if (action.equals(MediaControlIntent.ACTION_PLAY)) {
25457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    success = handlePlay(intent, callback);
25557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                } else if (action.equals(MediaControlIntent.ACTION_ENQUEUE)) {
25657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    success = handleEnqueue(intent, callback);
25757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                } else if (action.equals(MediaControlIntent.ACTION_REMOVE)) {
25857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    success = handleRemove(intent, callback);
25957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                } else if (action.equals(MediaControlIntent.ACTION_SEEK)) {
26057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    success = handleSeek(intent, callback);
26157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                } else if (action.equals(MediaControlIntent.ACTION_GET_STATUS)) {
26257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    success = handleGetStatus(intent, callback);
26357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                } else if (action.equals(MediaControlIntent.ACTION_PAUSE)) {
26457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    success = handlePause(intent, callback);
26557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                } else if (action.equals(MediaControlIntent.ACTION_RESUME)) {
26657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    success = handleResume(intent, callback);
26757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                } else if (action.equals(MediaControlIntent.ACTION_STOP)) {
26857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    success = handleStop(intent, callback);
269ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown                }
27057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                Log.d(TAG, mSessionManager.toString());
27157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                return success;
272ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            }
273ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown
27457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            if (action.equals(ACTION_GET_STATISTICS)
275ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown                    && intent.hasCategory(CATEGORY_SAMPLE_ROUTE)) {
276ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown                Bundle data = new Bundle();
27757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                data.putInt(DATA_PLAYBACK_COUNT, mEnqueueCount);
278ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown                if (callback != null) {
279fcb6a9d1caaf43ae41f859ebb58a4483b12475a1Jeff Brown                    callback.onResult(data);
280ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown                }
281ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown                return true;
282ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            }
283ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown            return false;
284ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown        }
28557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
28657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        private void setVolumeInternal(int volume) {
28757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            if (volume >= 0 && volume <= VOLUME_MAX) {
28857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                mVolume = volume;
28957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                Log.d(TAG, mRouteId + ": New volume is " + mVolume);
29057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                publishRoutes();
29157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
29257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        }
29357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
29457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        private boolean handlePlay(Intent intent, ControlRequestCallback callback) {
29557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
29657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            if (sid == null || mSessionManager.stop(sid)) {
29757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                Log.d(TAG, "handleEnqueue");
29857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                return handleEnqueue(intent, callback);
29957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
30057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            return false;
30157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        }
30257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
30357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        private boolean handleEnqueue(Intent intent, ControlRequestCallback callback) {
30457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            if (intent.getData() == null) {
30557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                return false;
30657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
30757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
30857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            mEnqueueCount +=1;
30957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
31057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            boolean enqueue = intent.getAction().equals(MediaControlIntent.ACTION_ENQUEUE);
31157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            Uri uri = intent.getData();
31257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
31357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            long pos = intent.getLongExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0);
31457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            Bundle metadata = intent.getBundleExtra(MediaControlIntent.EXTRA_ITEM_METADATA);
31557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            Bundle headers = intent.getBundleExtra(MediaControlIntent.EXTRA_ITEM_HTTP_HEADERS);
31657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            PendingIntent receiver = (PendingIntent)intent.getParcelableExtra(
31757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    MediaControlIntent.EXTRA_ITEM_STATUS_UPDATE_RECEIVER);
31857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
31957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            Log.d(TAG, mRouteId + ": Received " + (enqueue?"enqueue":"play") + " request"
32057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    + ", uri=" + uri
32157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    + ", sid=" + sid
32257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    + ", pos=" + pos
32357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    + ", metadata=" + metadata
32457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    + ", headers=" + headers
32557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    + ", receiver=" + receiver);
32657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            MediaQueueItem item = mSessionManager.enqueue(sid, uri, receiver);
32757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            if (callback != null) {
32857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                if (item != null) {
32957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    Bundle result = new Bundle();
33057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    result.putString(MediaControlIntent.EXTRA_SESSION_ID, item.getSessionId());
33157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    result.putString(MediaControlIntent.EXTRA_ITEM_ID, item.getItemId());
33257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS,
33357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                            item.getStatus().asBundle());
33457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    callback.onResult(result);
33557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                } else {
33657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    callback.onError("Failed to open " + uri.toString(), null);
33757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                }
33857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
33957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            return true;
34057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        }
34157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
34257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        private boolean handleRemove(Intent intent, ControlRequestCallback callback) {
34357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
34457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            String iid = intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID);
34557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            MediaQueueItem item = mSessionManager.remove(sid, iid);
34657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            if (callback != null) {
34757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                if (item != null) {
34857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    Bundle result = new Bundle();
34957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS,
35057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                            item.getStatus().asBundle());
35157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    callback.onResult(result);
35257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                } else {
35357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    callback.onError("Failed to remove" +
35457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                            ", sid=" + sid + ", iid=" + iid, null);
35557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                }
35657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
35757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            return (item != null);
35857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        }
35957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
36057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        private boolean handleSeek(Intent intent, ControlRequestCallback callback) {
36157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
36257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            String iid = intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID);
36357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            long pos = intent.getLongExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0);
36457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            Log.d(TAG, mRouteId + ": Received seek request, pos=" + pos);
36557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            MediaQueueItem item = mSessionManager.seek(sid, iid, pos);
36657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            if (callback != null) {
36757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                if (item != null) {
36857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    Bundle result = new Bundle();
36957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS,
37057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                            item.getStatus().asBundle());
37157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    callback.onResult(result);
37257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                } else {
37357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    callback.onError("Failed to seek" +
37457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                            ", sid=" + sid + ", iid=" + iid + ", pos=" + pos, null);
37557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                }
37657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
37757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            return (item != null);
37857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        }
37957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
38057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        private boolean handleGetStatus(Intent intent, ControlRequestCallback callback) {
38157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
38257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            String iid = intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID);
38357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            MediaQueueItem item = mSessionManager.getStatus(sid, iid);
38457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            if (callback != null) {
38557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                if (item != null) {
38657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    Bundle result = new Bundle();
38757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS,
38857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                            item.getStatus().asBundle());
38957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    callback.onResult(result);
39057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                } else {
39157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    callback.onError("Failed to get status" +
39257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                            ", sid=" + sid + ", iid=" + iid, null);
39357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                }
39457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
39557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            return (item != null);
39657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        }
39757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
39857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        private boolean handlePause(Intent intent, ControlRequestCallback callback) {
39957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
40057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            boolean success = mSessionManager.pause(sid);
40157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            if (callback != null) {
40257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                if (success) {
40357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    callback.onResult(null);
40457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                } else {
40557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    callback.onError("Failed to pause, sid=" + sid, null);
40657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                }
40757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
40857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            return success;
40957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        }
41057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
41157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        private boolean handleResume(Intent intent, ControlRequestCallback callback) {
41257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
41357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            boolean success = mSessionManager.resume(sid);
41457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            if (callback != null) {
41557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                if (success) {
41657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    callback.onResult(null);
41757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                } else {
41857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    callback.onError("Failed to resume, sid=" + sid, null);
41957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                }
42057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
42157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            return success;
42257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        }
42357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
42457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        private boolean handleStop(Intent intent, ControlRequestCallback callback) {
42557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
42657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            boolean success = mSessionManager.stop(sid);
42757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            if (callback != null) {
42857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                if (success) {
42957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    callback.onResult(null);
43057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                } else {
43157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    callback.onError("Failed to stop, sid=" + sid, null);
43257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                }
43357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
43457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            return success;
43557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        }
43657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
43757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        private void handleFinish(boolean error) {
43857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            MediaQueueItem item = mSessionManager.finish(error);
43957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            if (item != null) {
44057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                handleStatusChange(item);
44157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
44257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        }
44357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
44457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        private void handleStatusChange(MediaQueueItem item) {
44557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            if (item == null) {
44657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                item = mSessionManager.getCurrentItem();
44757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
44857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            if (item != null) {
44957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                PendingIntent receiver = item.getUpdateReceiver();
45057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                if (receiver != null) {
45157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    Intent intent = new Intent();
45257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, item.getSessionId());
45357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    intent.putExtra(MediaControlIntent.EXTRA_ITEM_ID, item.getItemId());
45457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    intent.putExtra(MediaControlIntent.EXTRA_ITEM_STATUS,
45557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                            item.getStatus().asBundle());
45657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    try {
45757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                        receiver.send(getContext(), 0, intent);
45857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                        Log.d(TAG, mRouteId + ": Sending status update from provider");
45957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    } catch (PendingIntent.CanceledException e) {
46057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                        Log.d(TAG, mRouteId + ": Failed to send status update!");
46157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                    }
46257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                }
46357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
46457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        }
46557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
46657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        private final class MediaPlayerCallback extends MediaPlayerWrapper.Callback {
46757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            @Override
46857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            public void onError() {
46957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                handleFinish(true);
47057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
47157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
47257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            @Override
47357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            public void onCompletion() {
47457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                handleFinish(false);
47557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
47657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
47757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            @Override
47857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            public void onStatusChanged() {
47957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                handleStatusChange(null);
48057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
48157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang
48257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            @Override
48357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            public void onSizeChanged(int width, int height) {
48457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang                mOverlay.updateAspectRatio(width, height);
48557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang            }
48657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang        }
487ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown    }
488ecdd1b114d4fb36682cdabe205e08e6f68f79f63Jeff Brown}