SystemMediaRouteProvider.java revision d11aa1784335270b8d85e385f2c8be79ee6a586c
1c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown/* 2c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Copyright (C) 2013 The Android Open Source Project 3c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 4c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 5c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * you may not use this file except in compliance with the License. 6c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * You may obtain a copy of the License at 7c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 8c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * http://www.apache.org/licenses/LICENSE-2.0 9c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 10c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Unless required by applicable law or agreed to in writing, software 11c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 12c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * See the License for the specific language governing permissions and 14c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * limitations under the License. 15c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 16c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 17b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brownpackage android.support.v7.media; 18c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 19c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.content.BroadcastReceiver; 20c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.content.Context; 21c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.content.Intent; 22c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.content.IntentFilter; 23b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brownimport android.content.res.Resources; 24c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.media.AudioManager; 25c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.os.Build; 26b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brownimport android.support.v7.mediarouter.R; 27c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.view.Display; 28c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 29c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport java.util.ArrayList; 3011417b1cfde8f1749905f2d735623af9214148afJeff Brownimport java.util.List; 31c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 32c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown/** 33c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Provides routes for built-in system destinations such as the local display 34c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * and speaker. On Jellybean and newer platform releases, queries the framework 35c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * MediaRouter for framework-provided routes and registers non-framework-provided 36c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * routes as user routes. 37c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 38c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownabstract class SystemMediaRouteProvider extends MediaRouteProvider { 39c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private static final String TAG = "SystemMediaRouteProvider"; 40c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 41fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public static final String PACKAGE_NAME = "android"; 42c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final String DEFAULT_ROUTE_ID = "DEFAULT_ROUTE"; 43c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 44c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected SystemMediaRouteProvider(Context context) { 45fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown super(context, new ProviderMetadata(PACKAGE_NAME)); 46c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 47c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 48c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static SystemMediaRouteProvider obtain(Context context, SyncCallback syncCallback) { 49c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (Build.VERSION.SDK_INT >= 18) { 50c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return new JellybeanMr2Impl(context, syncCallback); 51c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 52c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (Build.VERSION.SDK_INT >= 17) { 53c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return new JellybeanMr1Impl(context, syncCallback); 54c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 55c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (Build.VERSION.SDK_INT >= 16) { 56c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return new JellybeanImpl(context, syncCallback); 57c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 58c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return new LegacyImpl(context); 59c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 60c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 61c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 62c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Called by the media router when a route is added to synchronize state with 63c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * the framework media router. 64c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 65c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteAdded(MediaRouter.RouteInfo route) { 66c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 67c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 68c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 69c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Called by the media router when a route is removed to synchronize state with 70c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * the framework media router. 71c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 72c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteRemoved(MediaRouter.RouteInfo route) { 73c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 74c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 75c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 76c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Called by the media router when a route is changed to synchronize state with 77c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * the framework media router. 78c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 79c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteChanged(MediaRouter.RouteInfo route) { 80c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 81c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 82c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 83c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Called by the media router when a route is selected to synchronize state with 84c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * the framework media router. 85c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 86c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteSelected(MediaRouter.RouteInfo route) { 87c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 88c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 89c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 90c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Callbacks into the media router to synchronize state with the framework media router. 91c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 92c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public interface SyncCallback { 93c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public MediaRouter.RouteInfo getSystemRouteByDescriptorId(String id); 94c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 95c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 96c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 97c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Legacy implementation for platform versions prior to Jellybean. 98c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 99c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static class LegacyImpl extends SystemMediaRouteProvider { 100c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private static final int PLAYBACK_STREAM = AudioManager.STREAM_MUSIC; 101c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 10211417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final ArrayList<IntentFilter> CONTROL_FILTERS; 103fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown static { 10411417b1cfde8f1749905f2d735623af9214148afJeff Brown IntentFilter f = new IntentFilter(); 10511417b1cfde8f1749905f2d735623af9214148afJeff Brown f.addCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO); 10611417b1cfde8f1749905f2d735623af9214148afJeff Brown f.addCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO); 10711417b1cfde8f1749905f2d735623af9214148afJeff Brown 10811417b1cfde8f1749905f2d735623af9214148afJeff Brown CONTROL_FILTERS = new ArrayList<IntentFilter>(); 10911417b1cfde8f1749905f2d735623af9214148afJeff Brown CONTROL_FILTERS.add(f); 110fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 111fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 112c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final AudioManager mAudioManager; 113c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final VolumeChangeReceiver mVolumeChangeReceiver; 114c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mLastReportedVolume = -1; 115c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 116c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public LegacyImpl(Context context) { 117c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown super(context); 118c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); 119c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mVolumeChangeReceiver = new VolumeChangeReceiver(); 120c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 121c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown context.registerReceiver(mVolumeChangeReceiver, 122c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown new IntentFilter(VolumeChangeReceiver.VOLUME_CHANGED_ACTION)); 123c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown publishRoutes(); 124c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 125c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 126c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private void publishRoutes() { 127b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brown Resources r = getContext().getResources(); 12811417b1cfde8f1749905f2d735623af9214148afJeff Brown int maxVolume = mAudioManager.getStreamMaxVolume(PLAYBACK_STREAM); 129c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mLastReportedVolume = mAudioManager.getStreamVolume(PLAYBACK_STREAM); 13011417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteDescriptor defaultRoute = new MediaRouteDescriptor.Builder( 1313d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown DEFAULT_ROUTE_ID, r.getString(R.string.mr_system_route_name)) 13211417b1cfde8f1749905f2d735623af9214148afJeff Brown .addControlFilters(CONTROL_FILTERS) 13311417b1cfde8f1749905f2d735623af9214148afJeff Brown .setPlaybackStream(PLAYBACK_STREAM) 13411417b1cfde8f1749905f2d735623af9214148afJeff Brown .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_LOCAL) 13511417b1cfde8f1749905f2d735623af9214148afJeff Brown .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) 13611417b1cfde8f1749905f2d735623af9214148afJeff Brown .setVolumeMax(maxVolume) 13711417b1cfde8f1749905f2d735623af9214148afJeff Brown .setVolume(mLastReportedVolume) 13811417b1cfde8f1749905f2d735623af9214148afJeff Brown .build(); 13911417b1cfde8f1749905f2d735623af9214148afJeff Brown 14011417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor providerDescriptor = 14111417b1cfde8f1749905f2d735623af9214148afJeff Brown new MediaRouteProviderDescriptor.Builder() 14211417b1cfde8f1749905f2d735623af9214148afJeff Brown .addRoute(defaultRoute) 14311417b1cfde8f1749905f2d735623af9214148afJeff Brown .build(); 144c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown setDescriptor(providerDescriptor); 145c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 146c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 147c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 148c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteController onCreateRouteController(String routeId) { 149c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (routeId.equals(DEFAULT_ROUTE_ID)) { 150c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return new DefaultRouteController(); 151c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 152c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return null; 153c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 154c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 155c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final class DefaultRouteController extends RouteController { 156c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 157129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onSetVolume(int volume) { 158c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mAudioManager.setStreamVolume(PLAYBACK_STREAM, volume, 0); 159c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown publishRoutes(); 160c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 161c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 162c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 163129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onUpdateVolume(int delta) { 164c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int volume = mAudioManager.getStreamVolume(PLAYBACK_STREAM); 165c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int maxVolume = mAudioManager.getStreamMaxVolume(PLAYBACK_STREAM); 166c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int newVolume = Math.min(maxVolume, Math.max(0, volume + delta)); 167c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (newVolume != volume) { 168c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mAudioManager.setStreamVolume(PLAYBACK_STREAM, volume, 0); 169c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 170c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown publishRoutes(); 171c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 172c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 173c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 174c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final class VolumeChangeReceiver extends BroadcastReceiver { 175c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // These constants come from AudioManager. 176c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final String VOLUME_CHANGED_ACTION = 177c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown "android.media.VOLUME_CHANGED_ACTION"; 178c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final String EXTRA_VOLUME_STREAM_TYPE = 179c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown "android.media.EXTRA_VOLUME_STREAM_TYPE"; 180c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final String EXTRA_VOLUME_STREAM_VALUE = 181c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown "android.media.EXTRA_VOLUME_STREAM_VALUE"; 182c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 183c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 184c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onReceive(Context context, Intent intent) { 185c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (intent.getAction().equals(VOLUME_CHANGED_ACTION)) { 186c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final int streamType = intent.getIntExtra(EXTRA_VOLUME_STREAM_TYPE, -1); 187c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (streamType == PLAYBACK_STREAM) { 188c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final int volume = intent.getIntExtra(EXTRA_VOLUME_STREAM_VALUE, -1); 189c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (volume >= 0 && volume != mLastReportedVolume) { 190c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown publishRoutes(); 191c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 192c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 193c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 194c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 195c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 196c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 197c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 198c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 199c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Jellybean implementation. 200c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 201c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static class JellybeanImpl extends SystemMediaRouteProvider 202c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown implements MediaRouterJellybean.Callback, MediaRouterJellybean.VolumeCallback { 20311417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final ArrayList<IntentFilter> LIVE_AUDIO_CONTROL_FILTERS; 204fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown static { 20511417b1cfde8f1749905f2d735623af9214148afJeff Brown IntentFilter f = new IntentFilter(); 20611417b1cfde8f1749905f2d735623af9214148afJeff Brown f.addCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO); 207fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 20811417b1cfde8f1749905f2d735623af9214148afJeff Brown LIVE_AUDIO_CONTROL_FILTERS = new ArrayList<IntentFilter>(); 20911417b1cfde8f1749905f2d735623af9214148afJeff Brown LIVE_AUDIO_CONTROL_FILTERS.add(f); 210fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 211fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 21211417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final ArrayList<IntentFilter> LIVE_VIDEO_CONTROL_FILTERS; 213fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown static { 21411417b1cfde8f1749905f2d735623af9214148afJeff Brown IntentFilter f = new IntentFilter(); 21511417b1cfde8f1749905f2d735623af9214148afJeff Brown f.addCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO); 21611417b1cfde8f1749905f2d735623af9214148afJeff Brown 21711417b1cfde8f1749905f2d735623af9214148afJeff Brown LIVE_VIDEO_CONTROL_FILTERS = new ArrayList<IntentFilter>(); 21811417b1cfde8f1749905f2d735623af9214148afJeff Brown LIVE_VIDEO_CONTROL_FILTERS.add(f); 219fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 220fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 221c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final SyncCallback mSyncCallback; 222c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 223c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected final Object mRouterObj; 224c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected final Object mCallbackObj; 225c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected final Object mVolumeCallbackObj; 226c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected final Object mUserRouteCategoryObj; 22711417b1cfde8f1749905f2d735623af9214148afJeff Brown protected int mRouteTypes; 22811417b1cfde8f1749905f2d735623af9214148afJeff Brown protected boolean mActiveScan; 22911417b1cfde8f1749905f2d735623af9214148afJeff Brown protected boolean mCallbackRegistered; 230c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 231c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Maintains an association from framework routes to support library routes. 232c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Note that we cannot use the tag field for this because an application may 233c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // have published its own user routes to the framework media router and already 234c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // used the tag for its own purposes. 235c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected final ArrayList<SystemRouteRecord> mSystemRouteRecords = 236c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown new ArrayList<SystemRouteRecord>(); 237c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 238c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Maintains an association from support library routes to framework routes. 239c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected final ArrayList<UserRouteRecord> mUserRouteRecords = 240c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown new ArrayList<UserRouteRecord>(); 241c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 24211417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouterJellybean.SelectRouteWorkaround mSelectRouteWorkaround; 24311417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouterJellybean.GetDefaultRouteWorkaround mGetDefaultRouteWorkaround; 24411417b1cfde8f1749905f2d735623af9214148afJeff Brown 245c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public JellybeanImpl(Context context, SyncCallback syncCallback) { 246c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown super(context); 247c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mSyncCallback = syncCallback; 248c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRouterObj = MediaRouterJellybean.getMediaRouter(context); 249c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackObj = createCallbackObj(); 250c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mVolumeCallbackObj = createVolumeCallbackObj(); 251c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 252b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brown Resources r = context.getResources(); 253c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mUserRouteCategoryObj = MediaRouterJellybean.createRouteCategory( 2543d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown mRouterObj, r.getString(R.string.mr_user_route_category_name), false); 255c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 25611417b1cfde8f1749905f2d735623af9214148afJeff Brown updateSystemRoutes(); 257c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 258c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 259c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 26011417b1cfde8f1749905f2d735623af9214148afJeff Brown public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest request) { 26111417b1cfde8f1749905f2d735623af9214148afJeff Brown int newRouteTypes = 0; 26211417b1cfde8f1749905f2d735623af9214148afJeff Brown boolean newActiveScan = false; 26311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (request != null) { 26411417b1cfde8f1749905f2d735623af9214148afJeff Brown final MediaRouteSelector selector = request.getSelector(); 26511417b1cfde8f1749905f2d735623af9214148afJeff Brown final List<String> categories = selector.getControlCategories(); 26611417b1cfde8f1749905f2d735623af9214148afJeff Brown final int count = categories.size(); 26711417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < count; i++) { 26811417b1cfde8f1749905f2d735623af9214148afJeff Brown String category = categories.get(i); 26911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (category.equals(MediaControlIntent.CATEGORY_LIVE_AUDIO)) { 27011417b1cfde8f1749905f2d735623af9214148afJeff Brown newRouteTypes |= MediaRouterJellybean.ROUTE_TYPE_LIVE_AUDIO; 27111417b1cfde8f1749905f2d735623af9214148afJeff Brown } else if (category.equals(MediaControlIntent.CATEGORY_LIVE_VIDEO)) { 27211417b1cfde8f1749905f2d735623af9214148afJeff Brown newRouteTypes |= MediaRouterJellybean.ROUTE_TYPE_LIVE_VIDEO; 27311417b1cfde8f1749905f2d735623af9214148afJeff Brown } else { 27411417b1cfde8f1749905f2d735623af9214148afJeff Brown newRouteTypes |= MediaRouterJellybean.ROUTE_TYPE_USER; 27511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 276fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 27711417b1cfde8f1749905f2d735623af9214148afJeff Brown newActiveScan = request.isActiveScan(); 27811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 27911417b1cfde8f1749905f2d735623af9214148afJeff Brown 28011417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mRouteTypes != newRouteTypes || mActiveScan != newActiveScan) { 28111417b1cfde8f1749905f2d735623af9214148afJeff Brown mRouteTypes = newRouteTypes; 28211417b1cfde8f1749905f2d735623af9214148afJeff Brown mActiveScan = newActiveScan; 28311417b1cfde8f1749905f2d735623af9214148afJeff Brown updateCallback(); 28411417b1cfde8f1749905f2d735623af9214148afJeff Brown updateSystemRoutes(); 285c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 286c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 287c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 28811417b1cfde8f1749905f2d735623af9214148afJeff Brown @Override 28911417b1cfde8f1749905f2d735623af9214148afJeff Brown public void onRouteAdded(Object routeObj) { 29011417b1cfde8f1749905f2d735623af9214148afJeff Brown if (addSystemRouteNoPublish(routeObj)) { 29111417b1cfde8f1749905f2d735623af9214148afJeff Brown publishRoutes(); 29211417b1cfde8f1749905f2d735623af9214148afJeff Brown } 29311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 29411417b1cfde8f1749905f2d735623af9214148afJeff Brown 29511417b1cfde8f1749905f2d735623af9214148afJeff Brown private void updateSystemRoutes() { 29611417b1cfde8f1749905f2d735623af9214148afJeff Brown boolean changed = false; 297c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (Object routeObj : MediaRouterJellybean.getRoutes(mRouterObj)) { 29811417b1cfde8f1749905f2d735623af9214148afJeff Brown changed |= addSystemRouteNoPublish(routeObj); 29911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 30011417b1cfde8f1749905f2d735623af9214148afJeff Brown if (changed) { 30111417b1cfde8f1749905f2d735623af9214148afJeff Brown publishRoutes(); 302c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 303c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 304c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 30511417b1cfde8f1749905f2d735623af9214148afJeff Brown private boolean addSystemRouteNoPublish(Object routeObj) { 30611417b1cfde8f1749905f2d735623af9214148afJeff Brown if (getUserRouteRecord(routeObj) == null 30711417b1cfde8f1749905f2d735623af9214148afJeff Brown && findSystemRouteRecord(routeObj) < 0) { 308fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown boolean isDefault = (getDefaultRoute() == routeObj); 309fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown SystemRouteRecord record = new SystemRouteRecord(routeObj, isDefault); 310fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown updateSystemRouteDescriptor(record); 311fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemRouteRecords.add(record); 31211417b1cfde8f1749905f2d735623af9214148afJeff Brown return true; 313fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 31411417b1cfde8f1749905f2d735623af9214148afJeff Brown return false; 315c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 316c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 317c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 318c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteRemoved(Object routeObj) { 319fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (getUserRouteRecord(routeObj) == null) { 320fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int index = findSystemRouteRecord(routeObj); 321fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (index >= 0) { 322fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemRouteRecords.remove(index); 323fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown publishRoutes(); 324fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 325c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 326c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 327c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 328c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 329c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteChanged(Object routeObj) { 330fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (getUserRouteRecord(routeObj) == null) { 331fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int index = findSystemRouteRecord(routeObj); 332fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (index >= 0) { 333fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown SystemRouteRecord record = mSystemRouteRecords.get(index); 334fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown updateSystemRouteDescriptor(record); 335fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown publishRoutes(); 336fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 337c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 338c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 339c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 340c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 341c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteVolumeChanged(Object routeObj) { 342fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (getUserRouteRecord(routeObj) == null) { 343fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int index = findSystemRouteRecord(routeObj); 344fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (index >= 0) { 345fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown SystemRouteRecord record = mSystemRouteRecords.get(index); 346fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int newVolume = MediaRouterJellybean.RouteInfo.getVolume(routeObj); 347fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (newVolume != record.mRouteDescriptor.getVolume()) { 34811417b1cfde8f1749905f2d735623af9214148afJeff Brown record.mRouteDescriptor = 34911417b1cfde8f1749905f2d735623af9214148afJeff Brown new MediaRouteDescriptor.Builder(record.mRouteDescriptor) 35011417b1cfde8f1749905f2d735623af9214148afJeff Brown .setVolume(newVolume) 35111417b1cfde8f1749905f2d735623af9214148afJeff Brown .build(); 352fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown publishRoutes(); 353fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 354c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 355c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 356c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 357c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 358c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 359c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteSelected(int type, Object routeObj) { 36011417b1cfde8f1749905f2d735623af9214148afJeff Brown if (routeObj != MediaRouterJellybean.getSelectedRoute(mRouterObj, 36111417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybean.ALL_ROUTE_TYPES)) { 362fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // The currently selected route has already changed so this callback 363fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // is stale. Drop it to prevent getting into sync loops. 364fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return; 365fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 366fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 367fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown UserRouteRecord userRouteRecord = getUserRouteRecord(routeObj); 368fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (userRouteRecord != null) { 369fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown userRouteRecord.mRoute.select(); 370c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } else { 371c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Select the route if it already exists in the compat media router. 372c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // If not, we will select it instead when the route is added. 373c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int index = findSystemRouteRecord(routeObj); 374c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 375c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown SystemRouteRecord record = mSystemRouteRecords.get(index); 376c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouter.RouteInfo route = mSyncCallback.getSystemRouteByDescriptorId( 377c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRouteDescriptorId); 378c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (route != null) { 379c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown route.select(); 380c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 381c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 382c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 383c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 384c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 385c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 386c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteUnselected(int type, Object routeObj) { 387c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Nothing to do when a route is unselected. 388c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // We only need to handle when a route is selected. 389c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 390c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 391c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 392c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteGrouped(Object routeObj, Object groupObj, int index) { 393c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Route grouping is deprecated and no longer supported. 394c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 395c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 396c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 397c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteUngrouped(Object routeObj, Object groupObj) { 398c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Route grouping is deprecated and no longer supported. 399c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 400c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 401c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 402c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onVolumeSetRequest(Object routeObj, int volume) { 403fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown UserRouteRecord record = getUserRouteRecord(routeObj); 404fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (record != null) { 405c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRoute.requestSetVolume(volume); 406c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 407c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 408c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 409c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 410c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onVolumeUpdateRequest(Object routeObj, int direction) { 411fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown UserRouteRecord record = getUserRouteRecord(routeObj); 412fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (record != null) { 413c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRoute.requestUpdateVolume(direction); 414c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 415c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 416c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 417c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 418c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteAdded(MediaRouter.RouteInfo route) { 419fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (route.getProviderInstance() != this) { 420c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Object routeObj = MediaRouterJellybean.createUserRoute( 421c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRouterObj, mUserRouteCategoryObj); 422c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown UserRouteRecord record = new UserRouteRecord(route, routeObj); 423c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.RouteInfo.setTag(routeObj, record); 424c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setVolumeCallback(routeObj, mVolumeCallbackObj); 425c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown updateUserRouteProperties(record); 426c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mUserRouteRecords.add(record); 427c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.addUserRoute(mRouterObj, routeObj); 428c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } else { 429c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // If the newly added route is the counterpart of the currently selected 430c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // route in the framework media router then ensure it is selected in 431c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // the compat media router. 432c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Object routeObj = MediaRouterJellybean.getSelectedRoute( 43311417b1cfde8f1749905f2d735623af9214148afJeff Brown mRouterObj, MediaRouterJellybean.ALL_ROUTE_TYPES); 434c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int index = findSystemRouteRecord(routeObj); 435c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 436c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown SystemRouteRecord record = mSystemRouteRecords.get(index); 437c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (record.mRouteDescriptorId.equals(route.getDescriptorId())) { 438c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown route.select(); 439c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 440c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 441c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 442c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 443c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 444c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 445c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteRemoved(MediaRouter.RouteInfo route) { 446fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (route.getProviderInstance() != this) { 447c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int index = findUserRouteRecord(route); 448c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 449c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown UserRouteRecord record = mUserRouteRecords.remove(index); 450c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.RouteInfo.setTag(record.mRouteObj, null); 451c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setVolumeCallback(record.mRouteObj, null); 452c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.removeUserRoute(mRouterObj, record.mRouteObj); 453c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 454c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 455c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 456c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 457c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 458c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteChanged(MediaRouter.RouteInfo route) { 459fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (route.getProviderInstance() != this) { 460c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int index = findUserRouteRecord(route); 461c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 462c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown UserRouteRecord record = mUserRouteRecords.get(index); 463c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown updateUserRouteProperties(record); 464c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 465c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 466c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 467c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 468c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 469c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteSelected(MediaRouter.RouteInfo route) { 470fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (!route.isSelected()) { 471fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // The currently selected route has already changed so this callback 472fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // is stale. Drop it to prevent getting into sync loops. 473fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return; 474fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 475fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 476fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (route.getProviderInstance() != this) { 477c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int index = findUserRouteRecord(route); 478c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 479c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown UserRouteRecord record = mUserRouteRecords.get(index); 480c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown selectRoute(record.mRouteObj); 481c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 482c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } else { 483c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int index = findSystemRouteRecordByDescriptorId(route.getDescriptorId()); 484c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 485c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown SystemRouteRecord record = mSystemRouteRecords.get(index); 486c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown selectRoute(record.mRouteObj); 487c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 488c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 489c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 490c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 491c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected void publishRoutes() { 49211417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor.Builder builder = 493d11aa1784335270b8d85e385f2c8be79ee6a586cJeff Brown new MediaRouteProviderDescriptor.Builder(); 494c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int count = mSystemRouteRecords.size(); 495c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (int i = 0; i < count; i++) { 49611417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.addRoute(mSystemRouteRecords.get(i).mRouteDescriptor); 497c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 498c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 49911417b1cfde8f1749905f2d735623af9214148afJeff Brown setDescriptor(builder.build()); 500c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 501c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 502c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected int findSystemRouteRecord(Object routeObj) { 503c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final int count = mSystemRouteRecords.size(); 504c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (int i = 0; i < count; i++) { 505c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSystemRouteRecords.get(i).mRouteObj == routeObj) { 506c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return i; 507c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 508c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 509c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return -1; 510c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 511c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 512c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected int findSystemRouteRecordByDescriptorId(String id) { 513c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final int count = mSystemRouteRecords.size(); 514c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (int i = 0; i < count; i++) { 515c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSystemRouteRecords.get(i).mRouteDescriptorId.equals(id)) { 516c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return i; 517c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 518c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 519c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return -1; 520c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 521c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 522c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected int findUserRouteRecord(MediaRouter.RouteInfo route) { 523c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final int count = mUserRouteRecords.size(); 524c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (int i = 0; i < count; i++) { 525c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mUserRouteRecords.get(i).mRoute == route) { 526c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return i; 527c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 528c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 529c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return -1; 530c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 531c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 532fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown protected UserRouteRecord getUserRouteRecord(Object routeObj) { 533fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Object tag = MediaRouterJellybean.RouteInfo.getTag(routeObj); 534fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return tag instanceof UserRouteRecord ? (UserRouteRecord)tag : null; 535fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 536fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 537c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected void updateSystemRouteDescriptor(SystemRouteRecord record) { 538fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // We must always recreate the route descriptor when making any changes 539fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // because they are intended to be immutable once published. 540f6a2eb6ce9fef191df8368681ed5f825dcd24340Jeff Brown 541f6a2eb6ce9fef191df8368681ed5f825dcd24340Jeff Brown // Routes should not have null names but it may happen for badly configured 542f6a2eb6ce9fef191df8368681ed5f825dcd24340Jeff Brown // user routes. We tolerate this by using an empty name string here but 543f6a2eb6ce9fef191df8368681ed5f825dcd24340Jeff Brown // such unnamed routes will be discarded by the media router upstream 544f6a2eb6ce9fef191df8368681ed5f825dcd24340Jeff Brown // (with a log message so we can track down the problem). 545f6a2eb6ce9fef191df8368681ed5f825dcd24340Jeff Brown CharSequence name = MediaRouterJellybean.RouteInfo.getName( 546f6a2eb6ce9fef191df8368681ed5f825dcd24340Jeff Brown record.mRouteObj, getContext()); 54711417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteDescriptor.Builder builder = new MediaRouteDescriptor.Builder( 548f6a2eb6ce9fef191df8368681ed5f825dcd24340Jeff Brown record.mRouteDescriptorId, name != null ? name.toString() : ""); 54911417b1cfde8f1749905f2d735623af9214148afJeff Brown onBuildSystemRouteDescriptor(record, builder); 55011417b1cfde8f1749905f2d735623af9214148afJeff Brown record.mRouteDescriptor = builder.build(); 55111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 552c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 55311417b1cfde8f1749905f2d735623af9214148afJeff Brown protected void onBuildSystemRouteDescriptor(SystemRouteRecord record, 55411417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteDescriptor.Builder builder) { 555c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int supportedTypes = MediaRouterJellybean.RouteInfo.getSupportedTypes( 556c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRouteObj); 557c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if ((supportedTypes & MediaRouterJellybean.ROUTE_TYPE_LIVE_AUDIO) != 0) { 55811417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.addControlFilters(LIVE_AUDIO_CONTROL_FILTERS); 55911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 56011417b1cfde8f1749905f2d735623af9214148afJeff Brown if ((supportedTypes & MediaRouterJellybean.ROUTE_TYPE_LIVE_VIDEO) != 0) { 56111417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.addControlFilters(LIVE_VIDEO_CONTROL_FILTERS); 562c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 563c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 56411417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setPlaybackType( 565c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.RouteInfo.getPlaybackType(record.mRouteObj)); 56611417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setPlaybackStream( 567c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.RouteInfo.getPlaybackStream(record.mRouteObj)); 56811417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setVolume( 569c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.RouteInfo.getVolume(record.mRouteObj)); 57011417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setVolumeMax( 571c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.RouteInfo.getVolumeMax(record.mRouteObj)); 57211417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setVolumeHandling( 573c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.RouteInfo.getVolumeHandling(record.mRouteObj)); 574c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 575c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 576c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected void updateUserRouteProperties(UserRouteRecord record) { 577c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setName( 578c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRouteObj, record.mRoute.getName()); 579c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setPlaybackType( 580c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRouteObj, record.mRoute.getPlaybackType()); 581c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setPlaybackStream( 582c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRouteObj, record.mRoute.getPlaybackStream()); 583c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setVolume( 584c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRouteObj, record.mRoute.getVolume()); 585c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setVolumeMax( 586c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRouteObj, record.mRoute.getVolumeMax()); 587c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setVolumeHandling( 588c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRouteObj, record.mRoute.getVolumeHandling()); 589c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 590c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 59111417b1cfde8f1749905f2d735623af9214148afJeff Brown protected void updateCallback() { 59211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mCallbackRegistered) { 59311417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallbackRegistered = false; 59411417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybean.removeCallback(mRouterObj, mCallbackObj); 59511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 59611417b1cfde8f1749905f2d735623af9214148afJeff Brown 59711417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mRouteTypes != 0) { 59811417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallbackRegistered = true; 59911417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybean.addCallback(mRouterObj, mRouteTypes, mCallbackObj); 60011417b1cfde8f1749905f2d735623af9214148afJeff Brown } 60111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 60211417b1cfde8f1749905f2d735623af9214148afJeff Brown 603c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected Object createCallbackObj() { 604c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return MediaRouterJellybean.createCallback(this); 605c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 606c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 607c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected Object createVolumeCallbackObj() { 608c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return MediaRouterJellybean.createVolumeCallback(this); 609c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 610c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 611c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected void selectRoute(Object routeObj) { 61211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mSelectRouteWorkaround == null) { 61311417b1cfde8f1749905f2d735623af9214148afJeff Brown mSelectRouteWorkaround = new MediaRouterJellybean.SelectRouteWorkaround(); 614c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 61511417b1cfde8f1749905f2d735623af9214148afJeff Brown mSelectRouteWorkaround.selectRoute(mRouterObj, 61611417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybean.ALL_ROUTE_TYPES, routeObj); 617c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 618c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 619c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected Object getDefaultRoute() { 62011417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mGetDefaultRouteWorkaround == null) { 62111417b1cfde8f1749905f2d735623af9214148afJeff Brown mGetDefaultRouteWorkaround = new MediaRouterJellybean.GetDefaultRouteWorkaround(); 622c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 62311417b1cfde8f1749905f2d735623af9214148afJeff Brown return mGetDefaultRouteWorkaround.getDefaultRoute(mRouterObj); 624c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 625c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 626c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 627c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Represents a route that is provided by the framework media router 628c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * and published by this route provider to the support library media router. 629c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 630c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected static final class SystemRouteRecord { 631c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private static int sNextId; 632c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 633c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public final Object mRouteObj; 634c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public final String mRouteDescriptorId; 63511417b1cfde8f1749905f2d735623af9214148afJeff Brown public MediaRouteDescriptor mRouteDescriptor; // assigned immediately after creation 636c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 637c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public SystemRouteRecord(Object routeObj, boolean isDefault) { 638c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRouteObj = routeObj; 639c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRouteDescriptorId = isDefault ? DEFAULT_ROUTE_ID : "ROUTE_" + (sNextId++); 640c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 641c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 642c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 643c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 644c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Represents a route that is provided by the support library media router 645c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * and published by this route provider to the framework media router. 646c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 647c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected static final class UserRouteRecord { 648c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public final MediaRouter.RouteInfo mRoute; 649c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public final Object mRouteObj; 650c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 651c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public UserRouteRecord(MediaRouter.RouteInfo route, Object routeObj) { 652c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRoute = route; 653c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRouteObj = routeObj; 654c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 655c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 656c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 657c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 658c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 659c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Jellybean MR1 implementation. 660c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 661c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private static class JellybeanMr1Impl extends JellybeanImpl 662c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown implements MediaRouterJellybeanMr1.Callback { 66311417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouterJellybeanMr1.ActiveScanWorkaround mActiveScanWorkaround; 66411417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouterJellybeanMr1.IsConnectingWorkaround mIsConnectingWorkaround; 66511417b1cfde8f1749905f2d735623af9214148afJeff Brown 666c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public JellybeanMr1Impl(Context context, SyncCallback syncCallback) { 667c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown super(context, syncCallback); 668c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 669c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 670c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 671c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRoutePresentationDisplayChanged(Object routeObj) { 672c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int index = findSystemRouteRecord(routeObj); 673c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 674c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown SystemRouteRecord record = mSystemRouteRecords.get(index); 675c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Display newPresentationDisplay = 676c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybeanMr1.RouteInfo.getPresentationDisplay(routeObj); 677c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int newPresentationDisplayId = (newPresentationDisplay != null 678c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown ? newPresentationDisplay.getDisplayId() : -1); 679c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (newPresentationDisplayId 680c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown != record.mRouteDescriptor.getPresentationDisplayId()) { 68111417b1cfde8f1749905f2d735623af9214148afJeff Brown record.mRouteDescriptor = 68211417b1cfde8f1749905f2d735623af9214148afJeff Brown new MediaRouteDescriptor.Builder(record.mRouteDescriptor) 68311417b1cfde8f1749905f2d735623af9214148afJeff Brown .setPresentationDisplayId(newPresentationDisplayId) 68411417b1cfde8f1749905f2d735623af9214148afJeff Brown .build(); 685c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown publishRoutes(); 686c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 687c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 688c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 689c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 690c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 69111417b1cfde8f1749905f2d735623af9214148afJeff Brown protected void onBuildSystemRouteDescriptor(SystemRouteRecord record, 69211417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteDescriptor.Builder builder) { 69311417b1cfde8f1749905f2d735623af9214148afJeff Brown super.onBuildSystemRouteDescriptor(record, builder); 694c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 695c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (!MediaRouterJellybeanMr1.RouteInfo.isEnabled(record.mRouteObj)) { 69611417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setEnabled(false); 697c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 69811417b1cfde8f1749905f2d735623af9214148afJeff Brown 69911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (isConnecting(record)) { 70011417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setConnecting(true); 70111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 70211417b1cfde8f1749905f2d735623af9214148afJeff Brown 703c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Display presentationDisplay = 704c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybeanMr1.RouteInfo.getPresentationDisplay(record.mRouteObj); 705c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (presentationDisplay != null) { 70611417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setPresentationDisplayId(presentationDisplay.getDisplayId()); 707c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 708c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 709c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 710c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 71111417b1cfde8f1749905f2d735623af9214148afJeff Brown protected void updateCallback() { 71211417b1cfde8f1749905f2d735623af9214148afJeff Brown super.updateCallback(); 71311417b1cfde8f1749905f2d735623af9214148afJeff Brown 71411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mActiveScanWorkaround == null) { 71511417b1cfde8f1749905f2d735623af9214148afJeff Brown mActiveScanWorkaround = new MediaRouterJellybeanMr1.ActiveScanWorkaround( 71611417b1cfde8f1749905f2d735623af9214148afJeff Brown getContext(), getHandler()); 71711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 71811417b1cfde8f1749905f2d735623af9214148afJeff Brown mActiveScanWorkaround.setActiveScanRouteTypes(mActiveScan ? mRouteTypes : 0); 71911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 72011417b1cfde8f1749905f2d735623af9214148afJeff Brown 72111417b1cfde8f1749905f2d735623af9214148afJeff Brown @Override 722c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected Object createCallbackObj() { 723c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return MediaRouterJellybeanMr1.createCallback(this); 724c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 72511417b1cfde8f1749905f2d735623af9214148afJeff Brown 72611417b1cfde8f1749905f2d735623af9214148afJeff Brown protected boolean isConnecting(SystemRouteRecord record) { 72711417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mIsConnectingWorkaround == null) { 72811417b1cfde8f1749905f2d735623af9214148afJeff Brown mIsConnectingWorkaround = new MediaRouterJellybeanMr1.IsConnectingWorkaround(); 72911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 73011417b1cfde8f1749905f2d735623af9214148afJeff Brown return mIsConnectingWorkaround.isConnecting(record.mRouteObj); 73111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 732c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 733c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 734c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 735c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Jellybean MR2 implementation. 736c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 737c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private static class JellybeanMr2Impl extends JellybeanMr1Impl { 738c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public JellybeanMr2Impl(Context context, SyncCallback syncCallback) { 739c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown super(context, syncCallback); 740c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 741c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 742c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 743d63957d28aaabcec588b8cde12eac16414783aebJeff Brown protected void onBuildSystemRouteDescriptor(SystemRouteRecord record, 744d63957d28aaabcec588b8cde12eac16414783aebJeff Brown MediaRouteDescriptor.Builder builder) { 745d63957d28aaabcec588b8cde12eac16414783aebJeff Brown super.onBuildSystemRouteDescriptor(record, builder); 746d63957d28aaabcec588b8cde12eac16414783aebJeff Brown 747d63957d28aaabcec588b8cde12eac16414783aebJeff Brown CharSequence description = 748d63957d28aaabcec588b8cde12eac16414783aebJeff Brown MediaRouterJellybeanMr2.RouteInfo.getDescription(record.mRouteObj); 749d63957d28aaabcec588b8cde12eac16414783aebJeff Brown if (description != null) { 750d63957d28aaabcec588b8cde12eac16414783aebJeff Brown builder.setDescription(description.toString()); 751d63957d28aaabcec588b8cde12eac16414783aebJeff Brown } 752d63957d28aaabcec588b8cde12eac16414783aebJeff Brown } 753d63957d28aaabcec588b8cde12eac16414783aebJeff Brown 754d63957d28aaabcec588b8cde12eac16414783aebJeff Brown @Override 755c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected void selectRoute(Object routeObj) { 75611417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybean.selectRoute(mRouterObj, 75711417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybean.ALL_ROUTE_TYPES, routeObj); 758c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 759c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 760c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 761c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected Object getDefaultRoute() { 762c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return MediaRouterJellybeanMr2.getDefaultRoute(mRouterObj); 763c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 76411417b1cfde8f1749905f2d735623af9214148afJeff Brown 76511417b1cfde8f1749905f2d735623af9214148afJeff Brown @Override 766d63957d28aaabcec588b8cde12eac16414783aebJeff Brown protected void updateUserRouteProperties(UserRouteRecord record) { 767d63957d28aaabcec588b8cde12eac16414783aebJeff Brown super.updateUserRouteProperties(record); 768d63957d28aaabcec588b8cde12eac16414783aebJeff Brown 769d63957d28aaabcec588b8cde12eac16414783aebJeff Brown MediaRouterJellybeanMr2.UserRouteInfo.setDescription( 770d63957d28aaabcec588b8cde12eac16414783aebJeff Brown record.mRouteObj, record.mRoute.getDescription()); 771d63957d28aaabcec588b8cde12eac16414783aebJeff Brown } 772d63957d28aaabcec588b8cde12eac16414783aebJeff Brown 773d63957d28aaabcec588b8cde12eac16414783aebJeff Brown @Override 77411417b1cfde8f1749905f2d735623af9214148afJeff Brown protected void updateCallback() { 77511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mCallbackRegistered) { 77611417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybean.removeCallback(mRouterObj, mCallbackObj); 77711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 77811417b1cfde8f1749905f2d735623af9214148afJeff Brown 77911417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallbackRegistered = true; 78011417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybeanMr2.addCallback(mRouterObj, mRouteTypes, mCallbackObj, 78111417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS 782f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown | (mActiveScan ? MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN : 0)); 78311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 78411417b1cfde8f1749905f2d735623af9214148afJeff Brown 78511417b1cfde8f1749905f2d735623af9214148afJeff Brown @Override 78611417b1cfde8f1749905f2d735623af9214148afJeff Brown protected boolean isConnecting(SystemRouteRecord record) { 78711417b1cfde8f1749905f2d735623af9214148afJeff Brown return MediaRouterJellybeanMr2.RouteInfo.isConnecting(record.mRouteObj); 78811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 789c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 790c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown} 791