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; 20adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brownimport android.content.ComponentName; 21c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.content.Context; 22c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.content.Intent; 23c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.content.IntentFilter; 24b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brownimport android.content.res.Resources; 25c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.media.AudioManager; 26c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.os.Build; 27c69882cb9b130902c1554ef5d3e3b06d776cd796Alan Viveretteimport android.support.annotation.RequiresApi; 28b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brownimport android.support.v7.mediarouter.R; 29c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.view.Display; 30c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 31c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport java.util.ArrayList; 3211417b1cfde8f1749905f2d735623af9214148afJeff Brownimport java.util.List; 33cb63b6ecac9786891514f241dec71695f09d3efbJeff Brownimport java.util.Locale; 34c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 35c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown/** 36c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Provides routes for built-in system destinations such as the local display 37c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * and speaker. On Jellybean and newer platform releases, queries the framework 38c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * MediaRouter for framework-provided routes and registers non-framework-provided 39c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * routes as user routes. 40c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 41c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownabstract class SystemMediaRouteProvider extends MediaRouteProvider { 42c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private static final String TAG = "SystemMediaRouteProvider"; 43c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 44fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public static final String PACKAGE_NAME = "android"; 45c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final String DEFAULT_ROUTE_ID = "DEFAULT_ROUTE"; 46c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 47c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected SystemMediaRouteProvider(Context context) { 48adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown super(context, new ProviderMetadata(new ComponentName(PACKAGE_NAME, 49adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown SystemMediaRouteProvider.class.getName()))); 50c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 51c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 52c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static SystemMediaRouteProvider obtain(Context context, SyncCallback syncCallback) { 5396d4428ba99ad068679fca129e179e8187770d75Insun Kang if (Build.VERSION.SDK_INT >= 24) { 5496d4428ba99ad068679fca129e179e8187770d75Insun Kang return new Api24Impl(context, syncCallback); 5596d4428ba99ad068679fca129e179e8187770d75Insun Kang } 56c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (Build.VERSION.SDK_INT >= 18) { 57c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return new JellybeanMr2Impl(context, syncCallback); 58c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 59c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (Build.VERSION.SDK_INT >= 17) { 60c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return new JellybeanMr1Impl(context, syncCallback); 61c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 62c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (Build.VERSION.SDK_INT >= 16) { 63c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return new JellybeanImpl(context, syncCallback); 64c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 65c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return new LegacyImpl(context); 66c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 67c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 68c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 69c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Called by the media router when a route is added to synchronize state with 70c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * the framework media router. 71c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 72c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteAdded(MediaRouter.RouteInfo route) { 73c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 74c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 75c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 76c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Called by the media router when a route is removed to synchronize state with 77c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * the framework media router. 78c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 79c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteRemoved(MediaRouter.RouteInfo route) { 80c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 81c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 82c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 83c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Called by the media router when a route is changed to synchronize state with 84c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * the framework media router. 85c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 86c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteChanged(MediaRouter.RouteInfo route) { 87c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 88c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 89c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 90c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Called by the media router when a route is selected to synchronize state with 91c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * the framework media router. 92c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 93c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteSelected(MediaRouter.RouteInfo route) { 94c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 95c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 96c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 97c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Callbacks into the media router to synchronize state with the framework media router. 98c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 99c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public interface SyncCallback { 100ee4926b3033899028886c7407f75bcf55e708192Conrad Chen void onSystemRouteSelectedByDescriptorId(String id); 101c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 102c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 103c0b44f78f248e321d913db6077bf9a55976d7319Sungsoo protected Object getDefaultRoute() { 104c0b44f78f248e321d913db6077bf9a55976d7319Sungsoo return null; 105c0b44f78f248e321d913db6077bf9a55976d7319Sungsoo } 106c0b44f78f248e321d913db6077bf9a55976d7319Sungsoo 1076adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo protected Object getSystemRoute(MediaRouter.RouteInfo route) { 1086adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo return null; 1096adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo } 1106adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo 111c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 112c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Legacy implementation for platform versions prior to Jellybean. 113c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 114c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static class LegacyImpl extends SystemMediaRouteProvider { 115e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas static final int PLAYBACK_STREAM = AudioManager.STREAM_MUSIC; 116c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 11711417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final ArrayList<IntentFilter> CONTROL_FILTERS; 118fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown static { 11911417b1cfde8f1749905f2d735623af9214148afJeff Brown IntentFilter f = new IntentFilter(); 12011417b1cfde8f1749905f2d735623af9214148afJeff Brown f.addCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO); 12111417b1cfde8f1749905f2d735623af9214148afJeff Brown f.addCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO); 12211417b1cfde8f1749905f2d735623af9214148afJeff Brown 12311417b1cfde8f1749905f2d735623af9214148afJeff Brown CONTROL_FILTERS = new ArrayList<IntentFilter>(); 12411417b1cfde8f1749905f2d735623af9214148afJeff Brown CONTROL_FILTERS.add(f); 125fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 126fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 127e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas final AudioManager mAudioManager; 128c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final VolumeChangeReceiver mVolumeChangeReceiver; 129e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas int mLastReportedVolume = -1; 130c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 131c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public LegacyImpl(Context context) { 132c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown super(context); 133c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); 134c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mVolumeChangeReceiver = new VolumeChangeReceiver(); 135c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 136c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown context.registerReceiver(mVolumeChangeReceiver, 137c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown new IntentFilter(VolumeChangeReceiver.VOLUME_CHANGED_ACTION)); 138c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown publishRoutes(); 139c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 140c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 141e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas void publishRoutes() { 142b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brown Resources r = getContext().getResources(); 14311417b1cfde8f1749905f2d735623af9214148afJeff Brown int maxVolume = mAudioManager.getStreamMaxVolume(PLAYBACK_STREAM); 144c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mLastReportedVolume = mAudioManager.getStreamVolume(PLAYBACK_STREAM); 14511417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteDescriptor defaultRoute = new MediaRouteDescriptor.Builder( 1463d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown DEFAULT_ROUTE_ID, r.getString(R.string.mr_system_route_name)) 14711417b1cfde8f1749905f2d735623af9214148afJeff Brown .addControlFilters(CONTROL_FILTERS) 14811417b1cfde8f1749905f2d735623af9214148afJeff Brown .setPlaybackStream(PLAYBACK_STREAM) 14911417b1cfde8f1749905f2d735623af9214148afJeff Brown .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_LOCAL) 15011417b1cfde8f1749905f2d735623af9214148afJeff Brown .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) 15111417b1cfde8f1749905f2d735623af9214148afJeff Brown .setVolumeMax(maxVolume) 15211417b1cfde8f1749905f2d735623af9214148afJeff Brown .setVolume(mLastReportedVolume) 15311417b1cfde8f1749905f2d735623af9214148afJeff Brown .build(); 15411417b1cfde8f1749905f2d735623af9214148afJeff Brown 15511417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor providerDescriptor = 15611417b1cfde8f1749905f2d735623af9214148afJeff Brown new MediaRouteProviderDescriptor.Builder() 15711417b1cfde8f1749905f2d735623af9214148afJeff Brown .addRoute(defaultRoute) 15811417b1cfde8f1749905f2d735623af9214148afJeff Brown .build(); 159c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown setDescriptor(providerDescriptor); 160c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 161c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 162c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 163c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteController onCreateRouteController(String routeId) { 164c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (routeId.equals(DEFAULT_ROUTE_ID)) { 165c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return new DefaultRouteController(); 166c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 167c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return null; 168c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 169c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 170c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final class DefaultRouteController extends RouteController { 171c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 172129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onSetVolume(int volume) { 173c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mAudioManager.setStreamVolume(PLAYBACK_STREAM, volume, 0); 174c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown publishRoutes(); 175c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 176c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 177c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 178129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onUpdateVolume(int delta) { 179c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int volume = mAudioManager.getStreamVolume(PLAYBACK_STREAM); 180c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int maxVolume = mAudioManager.getStreamMaxVolume(PLAYBACK_STREAM); 181c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int newVolume = Math.min(maxVolume, Math.max(0, volume + delta)); 182c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (newVolume != volume) { 183c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mAudioManager.setStreamVolume(PLAYBACK_STREAM, volume, 0); 184c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 185c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown publishRoutes(); 186c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 187c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 188c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 189c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final class VolumeChangeReceiver extends BroadcastReceiver { 190c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // These constants come from AudioManager. 191c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final String VOLUME_CHANGED_ACTION = 192c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown "android.media.VOLUME_CHANGED_ACTION"; 193c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final String EXTRA_VOLUME_STREAM_TYPE = 194c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown "android.media.EXTRA_VOLUME_STREAM_TYPE"; 195c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final String EXTRA_VOLUME_STREAM_VALUE = 196c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown "android.media.EXTRA_VOLUME_STREAM_VALUE"; 197c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 198c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 199c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onReceive(Context context, Intent intent) { 200c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (intent.getAction().equals(VOLUME_CHANGED_ACTION)) { 201c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final int streamType = intent.getIntExtra(EXTRA_VOLUME_STREAM_TYPE, -1); 202c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (streamType == PLAYBACK_STREAM) { 203c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final int volume = intent.getIntExtra(EXTRA_VOLUME_STREAM_VALUE, -1); 204c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (volume >= 0 && volume != mLastReportedVolume) { 205c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown publishRoutes(); 206c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 207c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 208c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 209c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 210c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 211c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 212c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 213c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 214c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Jellybean implementation. 215c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 216c69882cb9b130902c1554ef5d3e3b06d776cd796Alan Viverette @RequiresApi(16) 217c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static class JellybeanImpl extends SystemMediaRouteProvider 218c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown implements MediaRouterJellybean.Callback, MediaRouterJellybean.VolumeCallback { 21911417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final ArrayList<IntentFilter> LIVE_AUDIO_CONTROL_FILTERS; 220fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown static { 22111417b1cfde8f1749905f2d735623af9214148afJeff Brown IntentFilter f = new IntentFilter(); 22211417b1cfde8f1749905f2d735623af9214148afJeff Brown f.addCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO); 223fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 22411417b1cfde8f1749905f2d735623af9214148afJeff Brown LIVE_AUDIO_CONTROL_FILTERS = new ArrayList<IntentFilter>(); 22511417b1cfde8f1749905f2d735623af9214148afJeff Brown LIVE_AUDIO_CONTROL_FILTERS.add(f); 226fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 227fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 22811417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final ArrayList<IntentFilter> LIVE_VIDEO_CONTROL_FILTERS; 229fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown static { 23011417b1cfde8f1749905f2d735623af9214148afJeff Brown IntentFilter f = new IntentFilter(); 23111417b1cfde8f1749905f2d735623af9214148afJeff Brown f.addCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO); 23211417b1cfde8f1749905f2d735623af9214148afJeff Brown 23311417b1cfde8f1749905f2d735623af9214148afJeff Brown LIVE_VIDEO_CONTROL_FILTERS = new ArrayList<IntentFilter>(); 23411417b1cfde8f1749905f2d735623af9214148afJeff Brown LIVE_VIDEO_CONTROL_FILTERS.add(f); 235fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 236fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 237c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final SyncCallback mSyncCallback; 238c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 239c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected final Object mRouterObj; 240c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected final Object mCallbackObj; 241c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected final Object mVolumeCallbackObj; 242c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected final Object mUserRouteCategoryObj; 24311417b1cfde8f1749905f2d735623af9214148afJeff Brown protected int mRouteTypes; 24411417b1cfde8f1749905f2d735623af9214148afJeff Brown protected boolean mActiveScan; 24511417b1cfde8f1749905f2d735623af9214148afJeff Brown protected boolean mCallbackRegistered; 246c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 247c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Maintains an association from framework routes to support library routes. 248c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Note that we cannot use the tag field for this because an application may 249c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // have published its own user routes to the framework media router and already 250c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // used the tag for its own purposes. 251c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected final ArrayList<SystemRouteRecord> mSystemRouteRecords = 252c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown new ArrayList<SystemRouteRecord>(); 253c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 254c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Maintains an association from support library routes to framework routes. 255c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected final ArrayList<UserRouteRecord> mUserRouteRecords = 256c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown new ArrayList<UserRouteRecord>(); 257c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 25811417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouterJellybean.SelectRouteWorkaround mSelectRouteWorkaround; 25911417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouterJellybean.GetDefaultRouteWorkaround mGetDefaultRouteWorkaround; 26011417b1cfde8f1749905f2d735623af9214148afJeff Brown 261c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public JellybeanImpl(Context context, SyncCallback syncCallback) { 262c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown super(context); 263c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mSyncCallback = syncCallback; 264c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRouterObj = MediaRouterJellybean.getMediaRouter(context); 265c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackObj = createCallbackObj(); 266c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mVolumeCallbackObj = createVolumeCallbackObj(); 267c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 268b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brown Resources r = context.getResources(); 269c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mUserRouteCategoryObj = MediaRouterJellybean.createRouteCategory( 2703d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown mRouterObj, r.getString(R.string.mr_user_route_category_name), false); 271c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 27211417b1cfde8f1749905f2d735623af9214148afJeff Brown updateSystemRoutes(); 273c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 274c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 275c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 27619e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown public RouteController onCreateRouteController(String routeId) { 27719e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown int index = findSystemRouteRecordByDescriptorId(routeId); 27819e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown if (index >= 0) { 27919e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown SystemRouteRecord record = mSystemRouteRecords.get(index); 28019e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown return new SystemRouteController(record.mRouteObj); 28119e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown } 28219e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown return null; 28319e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown } 28419e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown 28519e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown @Override 28611417b1cfde8f1749905f2d735623af9214148afJeff Brown public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest request) { 28711417b1cfde8f1749905f2d735623af9214148afJeff Brown int newRouteTypes = 0; 28811417b1cfde8f1749905f2d735623af9214148afJeff Brown boolean newActiveScan = false; 28911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (request != null) { 29011417b1cfde8f1749905f2d735623af9214148afJeff Brown final MediaRouteSelector selector = request.getSelector(); 29111417b1cfde8f1749905f2d735623af9214148afJeff Brown final List<String> categories = selector.getControlCategories(); 29211417b1cfde8f1749905f2d735623af9214148afJeff Brown final int count = categories.size(); 29311417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < count; i++) { 29411417b1cfde8f1749905f2d735623af9214148afJeff Brown String category = categories.get(i); 29511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (category.equals(MediaControlIntent.CATEGORY_LIVE_AUDIO)) { 29611417b1cfde8f1749905f2d735623af9214148afJeff Brown newRouteTypes |= MediaRouterJellybean.ROUTE_TYPE_LIVE_AUDIO; 29711417b1cfde8f1749905f2d735623af9214148afJeff Brown } else if (category.equals(MediaControlIntent.CATEGORY_LIVE_VIDEO)) { 29811417b1cfde8f1749905f2d735623af9214148afJeff Brown newRouteTypes |= MediaRouterJellybean.ROUTE_TYPE_LIVE_VIDEO; 29911417b1cfde8f1749905f2d735623af9214148afJeff Brown } else { 30011417b1cfde8f1749905f2d735623af9214148afJeff Brown newRouteTypes |= MediaRouterJellybean.ROUTE_TYPE_USER; 30111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 302fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 30311417b1cfde8f1749905f2d735623af9214148afJeff Brown newActiveScan = request.isActiveScan(); 30411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 30511417b1cfde8f1749905f2d735623af9214148afJeff Brown 30611417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mRouteTypes != newRouteTypes || mActiveScan != newActiveScan) { 30711417b1cfde8f1749905f2d735623af9214148afJeff Brown mRouteTypes = newRouteTypes; 30811417b1cfde8f1749905f2d735623af9214148afJeff Brown mActiveScan = newActiveScan; 30911417b1cfde8f1749905f2d735623af9214148afJeff Brown updateSystemRoutes(); 310c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 311c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 312c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 31311417b1cfde8f1749905f2d735623af9214148afJeff Brown @Override 31411417b1cfde8f1749905f2d735623af9214148afJeff Brown public void onRouteAdded(Object routeObj) { 31511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (addSystemRouteNoPublish(routeObj)) { 31611417b1cfde8f1749905f2d735623af9214148afJeff Brown publishRoutes(); 31711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 31811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 31911417b1cfde8f1749905f2d735623af9214148afJeff Brown 32011417b1cfde8f1749905f2d735623af9214148afJeff Brown private void updateSystemRoutes() { 321d38d8790c68d4d82a278d42e7f2a1382d005c637Sungsoo updateCallback(); 32211417b1cfde8f1749905f2d735623af9214148afJeff Brown boolean changed = false; 323c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (Object routeObj : MediaRouterJellybean.getRoutes(mRouterObj)) { 32411417b1cfde8f1749905f2d735623af9214148afJeff Brown changed |= addSystemRouteNoPublish(routeObj); 32511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 32611417b1cfde8f1749905f2d735623af9214148afJeff Brown if (changed) { 32711417b1cfde8f1749905f2d735623af9214148afJeff Brown publishRoutes(); 328c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 329c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 330c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 33111417b1cfde8f1749905f2d735623af9214148afJeff Brown private boolean addSystemRouteNoPublish(Object routeObj) { 33211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (getUserRouteRecord(routeObj) == null 33311417b1cfde8f1749905f2d735623af9214148afJeff Brown && findSystemRouteRecord(routeObj) < 0) { 334cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown String id = assignRouteId(routeObj); 335cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown SystemRouteRecord record = new SystemRouteRecord(routeObj, id); 336fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown updateSystemRouteDescriptor(record); 337fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemRouteRecords.add(record); 33811417b1cfde8f1749905f2d735623af9214148afJeff Brown return true; 339fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 34011417b1cfde8f1749905f2d735623af9214148afJeff Brown return false; 341c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 342c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 343cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown private String assignRouteId(Object routeObj) { 344cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown // TODO: The framework media router should supply a unique route id that 345cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown // we can use here. For now we use a hash of the route name and take care 346cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown // to dedupe it. 347cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown boolean isDefault = (getDefaultRoute() == routeObj); 348cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown String id = isDefault ? DEFAULT_ROUTE_ID : 349cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown String.format(Locale.US, "ROUTE_%08x", getRouteName(routeObj).hashCode()); 350cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown if (findSystemRouteRecordByDescriptorId(id) < 0) { 351cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown return id; 352cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown } 353cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown for (int i = 2; ; i++) { 354cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown String newId = String.format(Locale.US, "%s_%d", id, i); 355cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown if (findSystemRouteRecordByDescriptorId(newId) < 0) { 356cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown return newId; 357cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown } 358cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown } 359cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown } 360cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown 361c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 362c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteRemoved(Object routeObj) { 363fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (getUserRouteRecord(routeObj) == null) { 364fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int index = findSystemRouteRecord(routeObj); 365fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (index >= 0) { 366fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemRouteRecords.remove(index); 367fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown publishRoutes(); 368fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 369c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 370c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 371c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 372c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 373c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteChanged(Object routeObj) { 374fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (getUserRouteRecord(routeObj) == null) { 375fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int index = findSystemRouteRecord(routeObj); 376fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (index >= 0) { 377fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown SystemRouteRecord record = mSystemRouteRecords.get(index); 378fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown updateSystemRouteDescriptor(record); 379fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown publishRoutes(); 380fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 381c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 382c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 383c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 384c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 385c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteVolumeChanged(Object routeObj) { 386fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (getUserRouteRecord(routeObj) == null) { 387fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int index = findSystemRouteRecord(routeObj); 388fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (index >= 0) { 389fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown SystemRouteRecord record = mSystemRouteRecords.get(index); 390fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int newVolume = MediaRouterJellybean.RouteInfo.getVolume(routeObj); 391fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (newVolume != record.mRouteDescriptor.getVolume()) { 39211417b1cfde8f1749905f2d735623af9214148afJeff Brown record.mRouteDescriptor = 39311417b1cfde8f1749905f2d735623af9214148afJeff Brown new MediaRouteDescriptor.Builder(record.mRouteDescriptor) 39411417b1cfde8f1749905f2d735623af9214148afJeff Brown .setVolume(newVolume) 39511417b1cfde8f1749905f2d735623af9214148afJeff Brown .build(); 396fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown publishRoutes(); 397fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 398c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 399c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 400c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 401c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 402c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 403c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteSelected(int type, Object routeObj) { 40411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (routeObj != MediaRouterJellybean.getSelectedRoute(mRouterObj, 40511417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybean.ALL_ROUTE_TYPES)) { 406fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // The currently selected route has already changed so this callback 407fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // is stale. Drop it to prevent getting into sync loops. 408fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return; 409fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 410fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 411fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown UserRouteRecord userRouteRecord = getUserRouteRecord(routeObj); 412fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (userRouteRecord != null) { 413fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown userRouteRecord.mRoute.select(); 414c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } else { 415c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Select the route if it already exists in the compat media router. 416c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // If not, we will select it instead when the route is added. 417c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int index = findSystemRouteRecord(routeObj); 418c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 419c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown SystemRouteRecord record = mSystemRouteRecords.get(index); 420ee4926b3033899028886c7407f75bcf55e708192Conrad Chen mSyncCallback.onSystemRouteSelectedByDescriptorId(record.mRouteDescriptorId); 421c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 422c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 423c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 424c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 425c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 426c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteUnselected(int type, Object routeObj) { 427c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Nothing to do when a route is unselected. 428c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // We only need to handle when a route is selected. 429c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 430c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 431c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 432c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteGrouped(Object routeObj, Object groupObj, int index) { 433c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Route grouping is deprecated and no longer supported. 434c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 435c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 436c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 437c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteUngrouped(Object routeObj, Object groupObj) { 438c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Route grouping is deprecated and no longer supported. 439c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 440c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 441c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 442c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onVolumeSetRequest(Object routeObj, int volume) { 443fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown UserRouteRecord record = getUserRouteRecord(routeObj); 444fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (record != null) { 445c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRoute.requestSetVolume(volume); 446c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 447c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 448c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 449c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 450c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onVolumeUpdateRequest(Object routeObj, int direction) { 451fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown UserRouteRecord record = getUserRouteRecord(routeObj); 452fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (record != null) { 453c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRoute.requestUpdateVolume(direction); 454c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 455c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 456c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 457c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 458c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteAdded(MediaRouter.RouteInfo route) { 459fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (route.getProviderInstance() != this) { 460c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Object routeObj = MediaRouterJellybean.createUserRoute( 461c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRouterObj, mUserRouteCategoryObj); 462c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown UserRouteRecord record = new UserRouteRecord(route, routeObj); 463c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.RouteInfo.setTag(routeObj, record); 464c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setVolumeCallback(routeObj, mVolumeCallbackObj); 465c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown updateUserRouteProperties(record); 466c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mUserRouteRecords.add(record); 467c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.addUserRoute(mRouterObj, routeObj); 468c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } else { 469c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // If the newly added route is the counterpart of the currently selected 470c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // route in the framework media router then ensure it is selected in 471c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // the compat media router. 472c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Object routeObj = MediaRouterJellybean.getSelectedRoute( 47311417b1cfde8f1749905f2d735623af9214148afJeff Brown mRouterObj, MediaRouterJellybean.ALL_ROUTE_TYPES); 474c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int index = findSystemRouteRecord(routeObj); 475c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 476c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown SystemRouteRecord record = mSystemRouteRecords.get(index); 477c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (record.mRouteDescriptorId.equals(route.getDescriptorId())) { 478c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown route.select(); 479c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 480c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 481c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 482c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 483c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 484c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 485c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteRemoved(MediaRouter.RouteInfo route) { 486fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (route.getProviderInstance() != this) { 487c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int index = findUserRouteRecord(route); 488c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 489c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown UserRouteRecord record = mUserRouteRecords.remove(index); 490c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.RouteInfo.setTag(record.mRouteObj, null); 491c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setVolumeCallback(record.mRouteObj, null); 492c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.removeUserRoute(mRouterObj, record.mRouteObj); 493c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 494c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 495c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 496c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 497c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 498c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteChanged(MediaRouter.RouteInfo route) { 499fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (route.getProviderInstance() != this) { 500c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int index = findUserRouteRecord(route); 501c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 502c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown UserRouteRecord record = mUserRouteRecords.get(index); 503c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown updateUserRouteProperties(record); 504c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 505c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 506c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 507c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 508c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 509c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onSyncRouteSelected(MediaRouter.RouteInfo route) { 510fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (!route.isSelected()) { 511fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // The currently selected route has already changed so this callback 512fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // is stale. Drop it to prevent getting into sync loops. 513fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return; 514fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 515fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 516fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (route.getProviderInstance() != this) { 517c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int index = findUserRouteRecord(route); 518c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 519c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown UserRouteRecord record = mUserRouteRecords.get(index); 520c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown selectRoute(record.mRouteObj); 521c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 522c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } else { 523c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int index = findSystemRouteRecordByDescriptorId(route.getDescriptorId()); 524c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 525c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown SystemRouteRecord record = mSystemRouteRecords.get(index); 526c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown selectRoute(record.mRouteObj); 527c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 528c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 529c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 530c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 531c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected void publishRoutes() { 53211417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor.Builder builder = 533d11aa1784335270b8d85e385f2c8be79ee6a586cJeff Brown new MediaRouteProviderDescriptor.Builder(); 534c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int count = mSystemRouteRecords.size(); 535c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (int i = 0; i < count; i++) { 53611417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.addRoute(mSystemRouteRecords.get(i).mRouteDescriptor); 537c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 538c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 53911417b1cfde8f1749905f2d735623af9214148afJeff Brown setDescriptor(builder.build()); 540c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 541c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 542c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected int findSystemRouteRecord(Object routeObj) { 543c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final int count = mSystemRouteRecords.size(); 544c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (int i = 0; i < count; i++) { 545c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSystemRouteRecords.get(i).mRouteObj == routeObj) { 546c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return i; 547c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 548c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 549c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return -1; 550c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 551c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 552c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected int findSystemRouteRecordByDescriptorId(String id) { 553c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final int count = mSystemRouteRecords.size(); 554c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (int i = 0; i < count; i++) { 555c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSystemRouteRecords.get(i).mRouteDescriptorId.equals(id)) { 556c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return i; 557c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 558c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 559c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return -1; 560c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 561c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 562c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected int findUserRouteRecord(MediaRouter.RouteInfo route) { 563c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final int count = mUserRouteRecords.size(); 564c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (int i = 0; i < count; i++) { 565c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mUserRouteRecords.get(i).mRoute == route) { 566c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return i; 567c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 568c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 569c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return -1; 570c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 571c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 572fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown protected UserRouteRecord getUserRouteRecord(Object routeObj) { 573fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Object tag = MediaRouterJellybean.RouteInfo.getTag(routeObj); 574fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return tag instanceof UserRouteRecord ? (UserRouteRecord)tag : null; 575fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 576fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 577c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected void updateSystemRouteDescriptor(SystemRouteRecord record) { 578fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // We must always recreate the route descriptor when making any changes 579fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // because they are intended to be immutable once published. 580cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown MediaRouteDescriptor.Builder builder = new MediaRouteDescriptor.Builder( 581cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown record.mRouteDescriptorId, getRouteName(record.mRouteObj)); 582cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown onBuildSystemRouteDescriptor(record, builder); 583cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown record.mRouteDescriptor = builder.build(); 584cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown } 585f6a2eb6ce9fef191df8368681ed5f825dcd24340Jeff Brown 586cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown protected String getRouteName(Object routeObj) { 587f6a2eb6ce9fef191df8368681ed5f825dcd24340Jeff Brown // Routes should not have null names but it may happen for badly configured 588f6a2eb6ce9fef191df8368681ed5f825dcd24340Jeff Brown // user routes. We tolerate this by using an empty name string here but 589f6a2eb6ce9fef191df8368681ed5f825dcd24340Jeff Brown // such unnamed routes will be discarded by the media router upstream 590f6a2eb6ce9fef191df8368681ed5f825dcd24340Jeff Brown // (with a log message so we can track down the problem). 591cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown CharSequence name = MediaRouterJellybean.RouteInfo.getName(routeObj, getContext()); 592cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown return name != null ? name.toString() : ""; 59311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 594c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 59511417b1cfde8f1749905f2d735623af9214148afJeff Brown protected void onBuildSystemRouteDescriptor(SystemRouteRecord record, 59611417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteDescriptor.Builder builder) { 597c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int supportedTypes = MediaRouterJellybean.RouteInfo.getSupportedTypes( 598c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRouteObj); 599c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if ((supportedTypes & MediaRouterJellybean.ROUTE_TYPE_LIVE_AUDIO) != 0) { 60011417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.addControlFilters(LIVE_AUDIO_CONTROL_FILTERS); 60111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 60211417b1cfde8f1749905f2d735623af9214148afJeff Brown if ((supportedTypes & MediaRouterJellybean.ROUTE_TYPE_LIVE_VIDEO) != 0) { 60311417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.addControlFilters(LIVE_VIDEO_CONTROL_FILTERS); 604c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 605c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 60611417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setPlaybackType( 607c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.RouteInfo.getPlaybackType(record.mRouteObj)); 60811417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setPlaybackStream( 609c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.RouteInfo.getPlaybackStream(record.mRouteObj)); 61011417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setVolume( 611c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.RouteInfo.getVolume(record.mRouteObj)); 61211417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setVolumeMax( 613c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.RouteInfo.getVolumeMax(record.mRouteObj)); 61411417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setVolumeHandling( 615c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.RouteInfo.getVolumeHandling(record.mRouteObj)); 616c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 617c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 618c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected void updateUserRouteProperties(UserRouteRecord record) { 619c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setName( 620c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRouteObj, record.mRoute.getName()); 621c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setPlaybackType( 622c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRouteObj, record.mRoute.getPlaybackType()); 623c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setPlaybackStream( 624c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRouteObj, record.mRoute.getPlaybackStream()); 625c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setVolume( 626c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRouteObj, record.mRoute.getVolume()); 627c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setVolumeMax( 628c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRouteObj, record.mRoute.getVolumeMax()); 629c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybean.UserRouteInfo.setVolumeHandling( 630c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown record.mRouteObj, record.mRoute.getVolumeHandling()); 631c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 632c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 63311417b1cfde8f1749905f2d735623af9214148afJeff Brown protected void updateCallback() { 63411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mCallbackRegistered) { 63511417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallbackRegistered = false; 63611417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybean.removeCallback(mRouterObj, mCallbackObj); 63711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 63811417b1cfde8f1749905f2d735623af9214148afJeff Brown 63911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mRouteTypes != 0) { 64011417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallbackRegistered = true; 64111417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybean.addCallback(mRouterObj, mRouteTypes, mCallbackObj); 64211417b1cfde8f1749905f2d735623af9214148afJeff Brown } 64311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 64411417b1cfde8f1749905f2d735623af9214148afJeff Brown 645c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected Object createCallbackObj() { 646c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return MediaRouterJellybean.createCallback(this); 647c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 648c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 649c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected Object createVolumeCallbackObj() { 650c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return MediaRouterJellybean.createVolumeCallback(this); 651c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 652c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 653c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected void selectRoute(Object routeObj) { 65411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mSelectRouteWorkaround == null) { 65511417b1cfde8f1749905f2d735623af9214148afJeff Brown mSelectRouteWorkaround = new MediaRouterJellybean.SelectRouteWorkaround(); 656c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 65711417b1cfde8f1749905f2d735623af9214148afJeff Brown mSelectRouteWorkaround.selectRoute(mRouterObj, 65811417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybean.ALL_ROUTE_TYPES, routeObj); 659c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 660c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 661c0b44f78f248e321d913db6077bf9a55976d7319Sungsoo @Override 662c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected Object getDefaultRoute() { 66311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mGetDefaultRouteWorkaround == null) { 66411417b1cfde8f1749905f2d735623af9214148afJeff Brown mGetDefaultRouteWorkaround = new MediaRouterJellybean.GetDefaultRouteWorkaround(); 665c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 66611417b1cfde8f1749905f2d735623af9214148afJeff Brown return mGetDefaultRouteWorkaround.getDefaultRoute(mRouterObj); 667c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 668c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 6696adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo @Override 6706adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo protected Object getSystemRoute(MediaRouter.RouteInfo route) { 6716adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo if (route == null) { 6726adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo return null; 6736adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo } 6746adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo int index = findSystemRouteRecordByDescriptorId(route.getDescriptorId()); 6756adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo if (index >= 0) { 6766adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo return mSystemRouteRecords.get(index).mRouteObj; 6776adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo } 6786adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo return null; 6796adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo } 6806adc8ba4e18a8b97b0c6719975d7259f7a2500feSungsoo 681c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 682c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Represents a route that is provided by the framework media router 683c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * and published by this route provider to the support library media router. 684c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 685c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected static final class SystemRouteRecord { 686c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public final Object mRouteObj; 687c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public final String mRouteDescriptorId; 68811417b1cfde8f1749905f2d735623af9214148afJeff Brown public MediaRouteDescriptor mRouteDescriptor; // assigned immediately after creation 689c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 690cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown public SystemRouteRecord(Object routeObj, String id) { 691c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRouteObj = routeObj; 692cb63b6ecac9786891514f241dec71695f09d3efbJeff Brown mRouteDescriptorId = id; 693c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 694c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 695c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 696c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 697c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Represents a route that is provided by the support library media router 698c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * and published by this route provider to the framework media router. 699c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 700c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected static final class UserRouteRecord { 701c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public final MediaRouter.RouteInfo mRoute; 702c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public final Object mRouteObj; 703c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 704c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public UserRouteRecord(MediaRouter.RouteInfo route, Object routeObj) { 705c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRoute = route; 706c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRouteObj = routeObj; 707c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 708c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 70919e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown 71098ec0d5b378c8417156037af6389e90f0074a26eAurimas Liutikas protected static final class SystemRouteController extends RouteController { 71119e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown private final Object mRouteObj; 71219e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown 71319e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown public SystemRouteController(Object routeObj) { 71419e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown mRouteObj = routeObj; 71519e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown } 71619e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown 71719e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown @Override 71819e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown public void onSetVolume(int volume) { 71919e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown MediaRouterJellybean.RouteInfo.requestSetVolume(mRouteObj, volume); 72019e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown } 72119e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown 72219e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown @Override 72319e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown public void onUpdateVolume(int delta) { 72419e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown MediaRouterJellybean.RouteInfo.requestUpdateVolume(mRouteObj, delta); 72519e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown } 72619e77645aa6ce65b466d570375b36e2428f170b3Jeff Brown } 727c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 728c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 729c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 730c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Jellybean MR1 implementation. 731c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 732c69882cb9b130902c1554ef5d3e3b06d776cd796Alan Viverette @RequiresApi(17) 733c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private static class JellybeanMr1Impl extends JellybeanImpl 734c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown implements MediaRouterJellybeanMr1.Callback { 73511417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouterJellybeanMr1.ActiveScanWorkaround mActiveScanWorkaround; 73611417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouterJellybeanMr1.IsConnectingWorkaround mIsConnectingWorkaround; 73711417b1cfde8f1749905f2d735623af9214148afJeff Brown 738c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public JellybeanMr1Impl(Context context, SyncCallback syncCallback) { 739c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown super(context, syncCallback); 740c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 741c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 742c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 743c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRoutePresentationDisplayChanged(Object routeObj) { 744c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int index = findSystemRouteRecord(routeObj); 745c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 746c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown SystemRouteRecord record = mSystemRouteRecords.get(index); 747c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Display newPresentationDisplay = 748c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybeanMr1.RouteInfo.getPresentationDisplay(routeObj); 749c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int newPresentationDisplayId = (newPresentationDisplay != null 750c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown ? newPresentationDisplay.getDisplayId() : -1); 751c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (newPresentationDisplayId 752c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown != record.mRouteDescriptor.getPresentationDisplayId()) { 75311417b1cfde8f1749905f2d735623af9214148afJeff Brown record.mRouteDescriptor = 75411417b1cfde8f1749905f2d735623af9214148afJeff Brown new MediaRouteDescriptor.Builder(record.mRouteDescriptor) 75511417b1cfde8f1749905f2d735623af9214148afJeff Brown .setPresentationDisplayId(newPresentationDisplayId) 75611417b1cfde8f1749905f2d735623af9214148afJeff Brown .build(); 757c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown publishRoutes(); 758c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 759c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 760c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 761c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 762c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 76311417b1cfde8f1749905f2d735623af9214148afJeff Brown protected void onBuildSystemRouteDescriptor(SystemRouteRecord record, 76411417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteDescriptor.Builder builder) { 76511417b1cfde8f1749905f2d735623af9214148afJeff Brown super.onBuildSystemRouteDescriptor(record, builder); 766c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 767c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (!MediaRouterJellybeanMr1.RouteInfo.isEnabled(record.mRouteObj)) { 76811417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setEnabled(false); 769c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 77011417b1cfde8f1749905f2d735623af9214148afJeff Brown 77111417b1cfde8f1749905f2d735623af9214148afJeff Brown if (isConnecting(record)) { 77211417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setConnecting(true); 77311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 77411417b1cfde8f1749905f2d735623af9214148afJeff Brown 775c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Display presentationDisplay = 776c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouterJellybeanMr1.RouteInfo.getPresentationDisplay(record.mRouteObj); 777c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (presentationDisplay != null) { 77811417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.setPresentationDisplayId(presentationDisplay.getDisplayId()); 779c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 780c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 781c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 782c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 78311417b1cfde8f1749905f2d735623af9214148afJeff Brown protected void updateCallback() { 78411417b1cfde8f1749905f2d735623af9214148afJeff Brown super.updateCallback(); 78511417b1cfde8f1749905f2d735623af9214148afJeff Brown 78611417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mActiveScanWorkaround == null) { 78711417b1cfde8f1749905f2d735623af9214148afJeff Brown mActiveScanWorkaround = new MediaRouterJellybeanMr1.ActiveScanWorkaround( 78811417b1cfde8f1749905f2d735623af9214148afJeff Brown getContext(), getHandler()); 78911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 79011417b1cfde8f1749905f2d735623af9214148afJeff Brown mActiveScanWorkaround.setActiveScanRouteTypes(mActiveScan ? mRouteTypes : 0); 79111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 79211417b1cfde8f1749905f2d735623af9214148afJeff Brown 79311417b1cfde8f1749905f2d735623af9214148afJeff Brown @Override 794c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected Object createCallbackObj() { 795c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return MediaRouterJellybeanMr1.createCallback(this); 796c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 79711417b1cfde8f1749905f2d735623af9214148afJeff Brown 79811417b1cfde8f1749905f2d735623af9214148afJeff Brown protected boolean isConnecting(SystemRouteRecord record) { 79911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mIsConnectingWorkaround == null) { 80011417b1cfde8f1749905f2d735623af9214148afJeff Brown mIsConnectingWorkaround = new MediaRouterJellybeanMr1.IsConnectingWorkaround(); 80111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 80211417b1cfde8f1749905f2d735623af9214148afJeff Brown return mIsConnectingWorkaround.isConnecting(record.mRouteObj); 80311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 804c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 805c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 806c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 807c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Jellybean MR2 implementation. 808c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 809c69882cb9b130902c1554ef5d3e3b06d776cd796Alan Viverette @RequiresApi(18) 810c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private static class JellybeanMr2Impl extends JellybeanMr1Impl { 811c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public JellybeanMr2Impl(Context context, SyncCallback syncCallback) { 812c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown super(context, syncCallback); 813c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 814c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 815c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 816d63957d28aaabcec588b8cde12eac16414783aebJeff Brown protected void onBuildSystemRouteDescriptor(SystemRouteRecord record, 817d63957d28aaabcec588b8cde12eac16414783aebJeff Brown MediaRouteDescriptor.Builder builder) { 818d63957d28aaabcec588b8cde12eac16414783aebJeff Brown super.onBuildSystemRouteDescriptor(record, builder); 819d63957d28aaabcec588b8cde12eac16414783aebJeff Brown 820d63957d28aaabcec588b8cde12eac16414783aebJeff Brown CharSequence description = 821d63957d28aaabcec588b8cde12eac16414783aebJeff Brown MediaRouterJellybeanMr2.RouteInfo.getDescription(record.mRouteObj); 822d63957d28aaabcec588b8cde12eac16414783aebJeff Brown if (description != null) { 823d63957d28aaabcec588b8cde12eac16414783aebJeff Brown builder.setDescription(description.toString()); 824d63957d28aaabcec588b8cde12eac16414783aebJeff Brown } 825d63957d28aaabcec588b8cde12eac16414783aebJeff Brown } 826d63957d28aaabcec588b8cde12eac16414783aebJeff Brown 827d63957d28aaabcec588b8cde12eac16414783aebJeff Brown @Override 828c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected void selectRoute(Object routeObj) { 82911417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybean.selectRoute(mRouterObj, 83011417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybean.ALL_ROUTE_TYPES, routeObj); 831c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 832c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 833c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 834c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown protected Object getDefaultRoute() { 835c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return MediaRouterJellybeanMr2.getDefaultRoute(mRouterObj); 836c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 83711417b1cfde8f1749905f2d735623af9214148afJeff Brown 83811417b1cfde8f1749905f2d735623af9214148afJeff Brown @Override 839d63957d28aaabcec588b8cde12eac16414783aebJeff Brown protected void updateUserRouteProperties(UserRouteRecord record) { 840d63957d28aaabcec588b8cde12eac16414783aebJeff Brown super.updateUserRouteProperties(record); 841d63957d28aaabcec588b8cde12eac16414783aebJeff Brown 842d63957d28aaabcec588b8cde12eac16414783aebJeff Brown MediaRouterJellybeanMr2.UserRouteInfo.setDescription( 843d63957d28aaabcec588b8cde12eac16414783aebJeff Brown record.mRouteObj, record.mRoute.getDescription()); 844d63957d28aaabcec588b8cde12eac16414783aebJeff Brown } 845d63957d28aaabcec588b8cde12eac16414783aebJeff Brown 846d63957d28aaabcec588b8cde12eac16414783aebJeff Brown @Override 84711417b1cfde8f1749905f2d735623af9214148afJeff Brown protected void updateCallback() { 84811417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mCallbackRegistered) { 84911417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybean.removeCallback(mRouterObj, mCallbackObj); 85011417b1cfde8f1749905f2d735623af9214148afJeff Brown } 85111417b1cfde8f1749905f2d735623af9214148afJeff Brown 85211417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallbackRegistered = true; 85311417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouterJellybeanMr2.addCallback(mRouterObj, mRouteTypes, mCallbackObj, 85411417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS 855f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown | (mActiveScan ? MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN : 0)); 85611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 85711417b1cfde8f1749905f2d735623af9214148afJeff Brown 85811417b1cfde8f1749905f2d735623af9214148afJeff Brown @Override 85911417b1cfde8f1749905f2d735623af9214148afJeff Brown protected boolean isConnecting(SystemRouteRecord record) { 86011417b1cfde8f1749905f2d735623af9214148afJeff Brown return MediaRouterJellybeanMr2.RouteInfo.isConnecting(record.mRouteObj); 86111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 862c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 86396d4428ba99ad068679fca129e179e8187770d75Insun Kang 86496d4428ba99ad068679fca129e179e8187770d75Insun Kang /** 86596d4428ba99ad068679fca129e179e8187770d75Insun Kang * Api24 implementation. 86696d4428ba99ad068679fca129e179e8187770d75Insun Kang */ 867c69882cb9b130902c1554ef5d3e3b06d776cd796Alan Viverette @RequiresApi(24) 86896d4428ba99ad068679fca129e179e8187770d75Insun Kang private static class Api24Impl extends JellybeanMr2Impl { 86996d4428ba99ad068679fca129e179e8187770d75Insun Kang public Api24Impl(Context context, SyncCallback syncCallback) { 87096d4428ba99ad068679fca129e179e8187770d75Insun Kang super(context, syncCallback); 87196d4428ba99ad068679fca129e179e8187770d75Insun Kang } 87296d4428ba99ad068679fca129e179e8187770d75Insun Kang 87396d4428ba99ad068679fca129e179e8187770d75Insun Kang @Override 87496d4428ba99ad068679fca129e179e8187770d75Insun Kang protected void onBuildSystemRouteDescriptor(SystemRouteRecord record, 87596d4428ba99ad068679fca129e179e8187770d75Insun Kang MediaRouteDescriptor.Builder builder) { 87696d4428ba99ad068679fca129e179e8187770d75Insun Kang super.onBuildSystemRouteDescriptor(record, builder); 87796d4428ba99ad068679fca129e179e8187770d75Insun Kang 87896d4428ba99ad068679fca129e179e8187770d75Insun Kang builder.setDeviceType(MediaRouterApi24.RouteInfo.getDeviceType(record.mRouteObj)); 87996d4428ba99ad068679fca129e179e8187770d75Insun Kang } 88096d4428ba99ad068679fca129e179e8187770d75Insun Kang } 881c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown} 882