SlideShare a Scribd company logo
Integrando sua app 
Android com 
Chromecast 
Athila Santos 
athila@ciandt.com
Formado em Engenharia da Computação pela 
Universidade Federal de Itajubá em 2007. Trabalho 
com desenvolvimento Mobile desde então e com 
Android desde 2009 (Android 1.5) 
26
Ready to cast!
Cast device
Cast device 
Provedor de 
conteúdo
Cast device 
Renderizador 
Provedor de 
conteúdo
Cast device 
Renderizador 
Controle 
Provedor de 
conteúdo
Cast devices no mercado
Amazon Fire TV 
Roku 3 Apple TV Google 
Chromecast 
Processador Quad core Dual core Single core Single core 
Memória 2 GB 512 MB 512 MB 512 MB 
Controle 
Comando por 
voz; controle 
físico 
Controle físico; 
app iOS 
disponível 
Controle físico; 
app iOS 
Controlado por 
app (iOS, 
Android, Chrome) 
HDMI SIM SIM SIM SIM 
Preço $99 $99 $99 $35
Chromecast: Requisitos 
● Sender app
Chromecast: Requisitos 
● Sender app
Chromecast: Requisitos 
● Sender app 
● Receiver app
Chromecast: Requisitos 
● Sender app 
● Receiver app
Chromecast: Requisitos 
● Sender app 
● Receiver app 
Default Receiver (pronto para uso)
Chromecast: Requisitos 
● Sender app 
● Receiver app 
Default Receiver (pronto para uso) 
Styled Media Receiver 
Custom Receiver
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos 
● Sender app 
● Receiver app 
Default Receiver (pronto para uso) 
Styled Media Receiver 
Custom Receiver
Chromecast: Requisitos 
● Sender app 
● Receiver app 
Default Receiver (pronto para uso) 
Styled Media Receiver 
Custom Receiver 
Web browser limitado!
Chromecast: Application lifecycle
Chromecast: Application lifecycle
Chromecast: Application lifecycle
Chromecast: Application lifecycle 
App 
ID
Chromecast: Application lifecycle 
App 
ID 
App 
ID
Chromecast: Application lifecycle 
App 
ID 
App 
ID 
URL
Chromecast: Application lifecycle 
App 
ID 
App 
ID 
URL 
URL
Chromecast: Application lifecycle 
App 
ID 
App 
ID 
URL 
URL 
HTML
Chromecast: Application lifecycle 
App 
ID 
App 
ID 
URL 
URL 
HTML 
Canal de dados
The sender app
Sender app: Dependências
Sender app: Dependências 
● Android Support Library v7
Sender app: Dependências 
● Android Support Library v7 
● Android Support Media Router Library
Sender app: Dependências 
● Android Support Library v7 
● Android Support Media Router Library 
● Google Play Services
Sender app: Os passos para o sucesso... 
1. Descoberta de dispositivos 
2. Gerenciamento de sessão 
3. Transimissão de dados
Sender app: Os passos para o sucesso... 
1. Descoberta de dispositivos 
2. Gerenciamento de sessão 
3. Transimissão de dados
Sender app: Descoberta de dispositivos
Sender app: Descoberta de dispositivos
Sender app: Descoberta de dispositivos 
<?xml version="1.0" encoding="utf-8"?><menu 
xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:app="http://schemas.android.com/apk/res-auto" > 
<item 
android:id="@+id/media_route_menu_item" 
android:title="@string/media_route_menu_title" 
app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider" 
app:showAsAction="always"/></menu>
Descoberta de dispositivos: Media Router Selector
Descoberta de dispositivos: Media Router Selector 
public class MediaRouterPlaybackActivity extends ActionBarActivity { 
private MediaRouteSelector mSelector; 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
(...) 
// Create a route selector for the type of routes your app supports. 
mSelector = new MediaRouteSelector.Builder() 
// These are the framework-supported intents 
.addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO) 
.addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO) 
.addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) 
.build(); 
(...) 
} 
}
Descoberta de dispositivos: Media Router Selector 
public boolean onCreateOptionsMenu(Menu menu) { 
super.onCreateOptionsMenu(menu); 
// Inflate the menu and configure the media router action provider. 
getMenuInflater().inflate(R.menu.sample_media_router_menu, menu); 
// Attach the MediaRouteSelector to the menu item 
MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); 
MediaRouteActionProvider mediaRouteActionProvider = 
(MediaRouteActionProvider) MenuItemCompat.getActionProvider(mediaRouteMenuItem); 
mediaRouteActionProvider.setRouteSelector(mSelector); 
// Return true to show the menu. 
return true; 
}
Sender app: Os passos para o sucesso... 
1. Descoberta de dispositivos 
2. Gerenciamento de sessão 
3. Transimissão de dados
Sender app: Os passos para o sucesso... 
1. Descoberta de dispositivos 
2. Gerenciamento de sessão 
3. Transimissão de dados
Gerenciamento de sessão: Media Router Callback 
private final MediaRouter.Callback mMediaRouterCallback = new MediaRouter.Callback() { 
@Override 
public void onRouteSelected(MediaRouter router, RouteInfo route) { 
} 
@Override 
public void onRouteUnselected(MediaRouter router, RouteInfo route) { 
} 
@Override 
public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo route) { 
} 
}
Gerenciamento de sessão: Media Router Callback 
public class MediaRouterPlaybackActivity extends ActionBarActivity { 
protected void onCreate(Bundle savedInstanceState) { 
mMediaRouter = MediaRouter.getInstance(this); 
} 
public void onStart() { 
mMediaRouter.addCallback(mSelector, mMediaRouterCallback, 
MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); 
} 
public void onStop() { 
mMediaRouter.removeCallback(mMediaRouterCallback); 
super.onStop(); 
} 
}
Gerenciamento de sessão: Media Router Callback 
public class MediaRouterPlaybackActivity extends ActionBarActivity { 
protected void onCreate(Bundle savedInstanceState) { 
mMediaRouter = MediaRouter.getInstance(this); 
} 
public void onStart() { 
mMediaRouter.addCallback(mSelector, mMediaRouterCallback, 
MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); 
} 
public void onStop() { 
mMediaRouter.removeCallback(mMediaRouterCallback); 
super.onStop(); 
} 
}
Gerenciamento de sessão: Media Router Callback 
public class MediaRouterPlaybackActivity extends ActionBarActivity { 
protected void onCreate(Bundle savedInstanceState) { 
mMediaRouter = MediaRouter.getInstance(this); 
} 
public void onStart() { 
mMediaRouter.addCallback(mSelector, mMediaRouterCallback, 
MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); 
} 
public void onStop() { 
mMediaRouter.removeCallback(mMediaRouterCallback); 
super.onStop(); 
} 
}
Sender app: Os passos para o sucesso... 
1. Descoberta de dispositivos 
2. Gerenciamento de sessão 
3. Transimissão de dados
Sender app: Os passos para o sucesso... 
1. Descoberta de dispositivos 
2. Gerenciamento de sessão 
3. Transimissão de dados
Sender app: Os passos para o sucesso... 
1. Descoberta de dispositivos 
2. Gerenciamento de sessão 
3. Transimissão de dados
Transmissão de dados: Mensagem genérica 
Cast.CastApi.sendMessage (com.google.android.gms.common.api.GoogleApiClient, NAMESPACE, message) 
.setResultCallback ( 
new ResultCallback<Status>() { 
@Overridepublic void onResult(Status result) { 
if (!result.isSuccess()) { 
Log.e(TAG, "Sending message failed"); 
} 
} 
});
Transmissão de dados: Remote playback 
protected void onCreate(Bundle savedInstanceState) { 
Bundle mediaInfo = new Bundle(); 
mediaInfo.putString(MediaMetadata.KEY_TITLE, "Big Buck Bunny"); 
mediaInfo.putString(MediaMetadata.KEY_SUBTITLE, "Blender Foundation"); 
mediaInfo.putString(MediaMetadata.KEY_STUDIO, "Fusce id nisi turpis. Praesent viverra 
bibendum semper. Donec tristique, orci"); 
(...) 
}
Transmissão de dados: Remote playback 
public void onRouteSelected(MediaRouter router, RouteInfo route) { 
mRemotePlaybackClient = new RemotePlaybackClient(this, route); 
mRemotePlaybackClient.play(Uri.parse("http://meu_video.mp4"), 
"video/mp4", mediaInfo, 0, null, new ItemActionCallback() { 
@Override 
public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus, 
String itemId, MediaItemStatus itemStatus) { 
logStatus("play: succeeded for item " + itemId); 
} 
@Override 
public void onError(String error, int code, Bundle data) { 
} 
}); 
}
Google Cast User 
Guidelines
Google Cast User Guidelines 
https://developers.google.com/cast/docs/design_checklist#sender
Integrando sua app Android com Chromecast
Integrando sua app Android com Chromecast
CastCompanionLibrary - Registrando receiver app 
public class CastApplication extends Application { 
private static VideoCastManager mCastMgr = null; 
public static VideoCastManager getCastManager(Context context) { 
if (null == mCastMgr) { 
mCastMgr = VideoCastManager.initialize(context, APPLICATION_ID, null, null); 
} 
mCastMgr.setContext(context); 
return mCastMgr; 
} 
}
CastCompanionLibrary - Registrando receiver app 
public class CastApplication extends Application { 
private static VideoCastManager mCastMgr = null; 
public static VideoCastManager getCastManager(Context context) { 
if (null == mCastMgr) { 
mCastMgr = VideoCastManager.initialize(context, APPLICATION_ID, null, null); 
} 
mCastMgr.setContext(context); 
return mCastMgr; 
} 
} 
Default Receiver App: 
CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID
Sender app: Descoberta de dispositivos 
<?xml version="1.0" encoding="utf-8"?><menu 
xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:app="http://schemas.android.com/apk/res-auto" > 
<item 
android:id="@+id/media_route_menu_item" 
android:title="@string/media_route_menu_title" 
app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider" 
app:showAsAction="always"/></menu>
CastCompanionLibrary - Descoberta de devices 
public class PlayerActivity extends ActionBarActivity { 
private VideoCastManager mCastManager; 
private MediaInfo mSelectedMedia; 
private VideoCastConsumerImpl mCastConsumer; 
protected void onCreate(Bundle savedInstanceState) { 
mCastManager = CastApplication.getCastManager(this); 
} 
@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
super.onCreateOptionsMenu(menu); 
getMenuInflater().inflate(R.menu.main, menu); 
mCastManager.addMediaRouterButton(menu, R.id.media_route_menu_item); 
return true; 
} 
}
CastCompanionLibrary - Gerenciando sessão 
protected void onCreate(Bundle savedInstanceState) { 
mCastConsumer = new VideoCastConsumerImpl() { 
public void onApplicationConnected(ApplicationMetadata appMetadata, String sessionId, 
boolean wasLaunched) { } 
public void onApplicationDisconnected(int errorCode) { } 
public void onDisconnected() { } 
public void onRemoteMediaPlayerMetadataUpdated() { } 
public void onFailed(int resourceId, int statusCode) { } 
public void onConnectionSuspended(int cause) { } 
public void onConnectivityRecovered() { } 
}; 
} 
protected void onResume() { 
super.onResume(); 
mCastManager.addVideoCastConsumer(mCastConsumer); 
}
CastCompanionLibrary - Reproduzindo vídeo remoto 
protected void onCreate(Bundle savedInstanceState) { 
Bundle mediaInfo = new Bundle(); 
mediaInfo.putString(MediaMetadata.KEY_TITLE, "Big Buck Bunny"); 
mediaInfo.putString(MediaMetadata.KEY_SUBTITLE, "Blender Foundation"); 
mediaInfo.putString(MediaMetadata.KEY_STUDIO, "Fusce id nisi turpis. Praesent viverra bibendum 
semper. Donec tristique, orci"); 
mediaInfo.putString(com.google.sample.castcompanionlibrary.utils.Utils.KEY_URL, http://url.mp4); 
mediaInfo.putString(com.google.sample.castcompanionlibrary.utils.Utils.KEY_CONTENT_TYPE, 
"video/mp4"); 
ArrayList<String> images = new ArrayList<String>(); 
images.add("http://image_url_480"); 
images.add("http://image_url_720"); 
mediaInfo.putStringArrayList(com.google.sample.castcompanionlibrary.utils.Utils.KEY_IMAGES, 
images); 
mSelectedMediaInfo = com.google.sample.castcompanionlibrary.utils.Utils.toMediaInfo(mediaInfo); 
}
CastCompanionLibrary - Reproduzindo vídeo remoto 
mediaInfo.putString(MediaMetadata.KEY_TITLE, "Big Buck Bunny");
CastCompanionLibrary - Reproduzindo vídeo remoto 
mediaInfo.putString(MediaMetadata.KEY_TITLE, "Big Buck Bunny");
CastCompanionLibrary - Reproduzindo vídeo remoto 
mediaInfo.putString(MediaMetadata.KEY_SUBTITLE, "Blender Foundation");
CastCompanionLibrary - Reproduzindo vídeo remoto 
mediaInfo.putString(MediaMetadata.KEY_SUBTITLE, "Blender Foundation");
CastCompanionLibrary - Reproduzindo vídeo remoto 
mediaInfo.putString(MediaMetadata.KEY_STUDIO, "Fusce id nisi turpis. Praesent viverra bibendum 
semper. Donec tristique, orci");
CastCompanionLibrary - Reproduzindo vídeo remoto 
mediaInfo.putString(MediaMetadata.KEY_STUDIO, "Fusce id nisi turpis. Praesent viverra bibendum 
semper. Donec tristique, orci");
CastCompanionLibrary - Reproduzindo vídeo remoto 
images.add("http://image_url_480");
CastCompanionLibrary - Reproduzindo vídeo remoto 
images.add("http://image_url_480");
CastCompanionLibrary - Reproduzindo vídeo remoto 
public void onApplicationConnected(ApplicationMetadata appMetadata, 
String sessionId, boolean wasLaunched) { 
if (null != mSelectedMedia) { 
mCastManager.startCastControllerActivity(this, mSelectedMedia, 0, true); 
finish(); 
return; 
} 
}
CastCompanionLibrary - Reproduzindo vídeo remoto
Brindes da CCL
CastControllerActivity
CCL - CastControllerActivity
CCL - CastControllerActivity
CCL - CastControllerActivity 
images.add("http://image_url_720");
CCL - CastControllerActivity 
<activity 
android:name="com.google.sample.castcompanionlibrary.cast.player.VideoCastControllerActivity" 
android:launchMode="singleTask" 
android:screenOrientation="portrait" 
android:theme="@style/Theme.CastVideoOverlayYellow" > 
<meta-data 
android:name="android.support.PARENT_ACTIVITY" 
android:value="<parentActivity>" /> 
<intent-filter> 
<action android:name="android.intent.action.MAIN" /> 
</intent-filter> 
</activity>
MiniController
CCL - MiniController
CCL - MiniController
CCL - MiniController 
<com.google.sample.castcompanionlibrary.widgets.MiniController 
android:id="@+id/miniController1" 
android:layout_width="fill_parent" 
android:layout_height="wrap_content" 
android:layout_alignParentBottom="true" 
android:visibility="gone" > 
</com.google.sample.castcompanionlibrary.widgets.MiniController>
CCL - MiniController 
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
// -- Adding MiniController 
mMini = (MiniController) findViewById(R.id.miniController1); 
mCastManager.addMiniController(mMini); 
} 
protected void onDestroy() { 
if (null != mCastManager) { 
mCastManager.removeMiniController(mMini); 
} 
super.onDestroy(); 
}
OnGoing Notification
CCL - OnGoing Notification
CCL - OnGoing Notification
CCL - OnGoing Notification 
<receiver android:name="com.google.sample.castcompanionlibrary.remotecontrol.VideoIntentReceiver" > 
<intent-filter> 
<action android:name="com.google.sample.castcompanionlibrary.action.toggleplayback" /> 
<action android:name="com.google.sample.castcompanionlibrary.action.stop" /> 
</intent-filter> 
</receiver> 
<service 
android:name="com.google.sample.castcompanionlibrary.notification.VideoCastNotificationService" 
android:exported="false" > 
<intent-filter> 
<action android:name="com.google.sample.castcompanionlibrary.action.toggleplayback" /> 
<action android:name="com.google.sample.castcompanionlibrary.action.stop" /> 
<action android:name="com.google.sample.castcompanionlibrary.action.notificationvisibility" /> 
</intent-filter></service>
CCL - OnGoing Notification 
protected void onResume() { 
mCastManager = CastApplication.getCastManager(this); 
mCastManager.incrementUiCounter(); 
} 
protected void onPause() { 
mCastManager.decrementUiCounter(); 
} 
public class CastApplication extends Application { 
private static VideoCastManager mCastMgr = null; 
public static VideoCastManager getCastManager(Context context) { 
mCastMgr = VideoCastManager.initialize(context, APPLICATION_ID, null, null); 
mCastMgr.enableFeatures(VideoCastManager.FEATURE_NOTIFICATION ); 
return mCastMgr; 
} 
}
Lock Screen
CCL - Lock Screen
CCL - LockScreen 
public class CastApplication extends Application { 
private static VideoCastManager mCastMgr = null; 
public static VideoCastManager getCastManager(Context context) { 
mCastMgr = VideoCastManager.initialize(context, APPLICATION_ID, null, null); 
mCastMgr.enableFeatures(VideoCastManager.FEATURE_NOTIFICATION | 
VideoCastManager.FEATURE_LOCKSCREEN); 
return mCastMgr; 
} 
}
Integrando sua app Android com Chromecast
CCL RULES!!!!!
Obrigado! 
Athila Santos 
athila@ciandt.com 
athilahs@gmail.com 
br.linkedin.com/pub/athila-henrique-dos-santos/ 
6/41/744/

More Related Content

PDF
3D Game development using Blender and Java
PDF
Desenvolver para Chromecast
PDF
The unconventional devices for the Android video streaming
PDF
The unconventional devices for the video streaming in Android
ODP
Android App Development - 14 location, media and notifications
PDF
Eddystone beacons demo
PPTX
Custom Chromecast Receiver Application
PPTX
What's new in android jakarta gdg (2015-08-26)
3D Game development using Blender and Java
Desenvolver para Chromecast
The unconventional devices for the Android video streaming
The unconventional devices for the video streaming in Android
Android App Development - 14 location, media and notifications
Eddystone beacons demo
Custom Chromecast Receiver Application
What's new in android jakarta gdg (2015-08-26)

Similar to Integrando sua app Android com Chromecast (20)

PPTX
Developing for Chromecast on Android
PDF
Jollen's Presentation: Introducing Android low-level
PPT
Android Froyo
PDF
What's new in Android P @ I/O Extended Bangkok 2018
ODP
Android App Development - 13 Broadcast receivers and app widgets
PPTX
Android & Beacons
PDF
What's new in Android O
PPT
Synapseindia android application development tutorial
PPT
Synapseindia android apps development tutorial
PPT
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...
PPTX
From newbie to ...
PDF
Cross-platform mobile apps with Apache Cordova
PDF
Implementing cast in android
PPTX
BroadcastReceivers in Android
PDF
WebRTC & Firefox OS - presentation at Google
PDF
[2015/2016] Apache Cordova APIs
PPT
Scmad Chapter13
PDF
softshake 2014 - Java EE
ODP
Android For All The Things
KEY
Android workshop
Developing for Chromecast on Android
Jollen's Presentation: Introducing Android low-level
Android Froyo
What's new in Android P @ I/O Extended Bangkok 2018
Android App Development - 13 Broadcast receivers and app widgets
Android & Beacons
What's new in Android O
Synapseindia android application development tutorial
Synapseindia android apps development tutorial
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...
From newbie to ...
Cross-platform mobile apps with Apache Cordova
Implementing cast in android
BroadcastReceivers in Android
WebRTC & Firefox OS - presentation at Google
[2015/2016] Apache Cordova APIs
Scmad Chapter13
softshake 2014 - Java EE
Android For All The Things
Android workshop
Ad

Recently uploaded (10)

PDF
Best 4 Sites for Buy Verified Cash App Accounts – BTC Only.pdf
PDF
Kids, Screens & Emotional Development by Meenakshi Khakat
DOC
NIU毕业证学历认证,阿比林基督大学毕业证留学生学历
DOC
SIUE毕业证学历认证,阿祖萨太平洋大学毕业证学位证书复制
PPTX
Social Media People PowerPoint Templates.pptx
PDF
2025 Guide to Buy Verified Cash App Accounts You Can Trust.pdf
PPTX
ASMS Telecommunication company Profile
DOC
Camb毕业证学历认证,格罗斯泰斯特主教大学毕业证仿冒文凭毕业证
PDF
Lesson 13- HEREDITY _ pedSAWEREGFVCXZDSASEWFigree.pdf
PPTX
Introduction to Packet Tracer Course Overview - Aug 21 (1).pptx
Best 4 Sites for Buy Verified Cash App Accounts – BTC Only.pdf
Kids, Screens & Emotional Development by Meenakshi Khakat
NIU毕业证学历认证,阿比林基督大学毕业证留学生学历
SIUE毕业证学历认证,阿祖萨太平洋大学毕业证学位证书复制
Social Media People PowerPoint Templates.pptx
2025 Guide to Buy Verified Cash App Accounts You Can Trust.pdf
ASMS Telecommunication company Profile
Camb毕业证学历认证,格罗斯泰斯特主教大学毕业证仿冒文凭毕业证
Lesson 13- HEREDITY _ pedSAWEREGFVCXZDSASEWFigree.pdf
Introduction to Packet Tracer Course Overview - Aug 21 (1).pptx
Ad

Integrando sua app Android com Chromecast

  • 1. Integrando sua app Android com Chromecast Athila Santos athila@ciandt.com
  • 2. Formado em Engenharia da Computação pela Universidade Federal de Itajubá em 2007. Trabalho com desenvolvimento Mobile desde então e com Android desde 2009 (Android 1.5) 26
  • 5. Cast device Provedor de conteúdo
  • 6. Cast device Renderizador Provedor de conteúdo
  • 7. Cast device Renderizador Controle Provedor de conteúdo
  • 8. Cast devices no mercado
  • 9. Amazon Fire TV Roku 3 Apple TV Google Chromecast Processador Quad core Dual core Single core Single core Memória 2 GB 512 MB 512 MB 512 MB Controle Comando por voz; controle físico Controle físico; app iOS disponível Controle físico; app iOS Controlado por app (iOS, Android, Chrome) HDMI SIM SIM SIM SIM Preço $99 $99 $99 $35
  • 12. Chromecast: Requisitos ● Sender app ● Receiver app
  • 13. Chromecast: Requisitos ● Sender app ● Receiver app
  • 14. Chromecast: Requisitos ● Sender app ● Receiver app Default Receiver (pronto para uso)
  • 15. Chromecast: Requisitos ● Sender app ● Receiver app Default Receiver (pronto para uso) Styled Media Receiver Custom Receiver
  • 27. Chromecast: Requisitos ● Sender app ● Receiver app Default Receiver (pronto para uso) Styled Media Receiver Custom Receiver
  • 28. Chromecast: Requisitos ● Sender app ● Receiver app Default Receiver (pronto para uso) Styled Media Receiver Custom Receiver Web browser limitado!
  • 35. Chromecast: Application lifecycle App ID App ID URL URL
  • 36. Chromecast: Application lifecycle App ID App ID URL URL HTML
  • 37. Chromecast: Application lifecycle App ID App ID URL URL HTML Canal de dados
  • 40. Sender app: Dependências ● Android Support Library v7
  • 41. Sender app: Dependências ● Android Support Library v7 ● Android Support Media Router Library
  • 42. Sender app: Dependências ● Android Support Library v7 ● Android Support Media Router Library ● Google Play Services
  • 43. Sender app: Os passos para o sucesso... 1. Descoberta de dispositivos 2. Gerenciamento de sessão 3. Transimissão de dados
  • 44. Sender app: Os passos para o sucesso... 1. Descoberta de dispositivos 2. Gerenciamento de sessão 3. Transimissão de dados
  • 45. Sender app: Descoberta de dispositivos
  • 46. Sender app: Descoberta de dispositivos
  • 47. Sender app: Descoberta de dispositivos <?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/media_route_menu_item" android:title="@string/media_route_menu_title" app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider" app:showAsAction="always"/></menu>
  • 48. Descoberta de dispositivos: Media Router Selector
  • 49. Descoberta de dispositivos: Media Router Selector public class MediaRouterPlaybackActivity extends ActionBarActivity { private MediaRouteSelector mSelector; @Override protected void onCreate(Bundle savedInstanceState) { (...) // Create a route selector for the type of routes your app supports. mSelector = new MediaRouteSelector.Builder() // These are the framework-supported intents .addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO) .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO) .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) .build(); (...) } }
  • 50. Descoberta de dispositivos: Media Router Selector public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); // Inflate the menu and configure the media router action provider. getMenuInflater().inflate(R.menu.sample_media_router_menu, menu); // Attach the MediaRouteSelector to the menu item MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat.getActionProvider(mediaRouteMenuItem); mediaRouteActionProvider.setRouteSelector(mSelector); // Return true to show the menu. return true; }
  • 51. Sender app: Os passos para o sucesso... 1. Descoberta de dispositivos 2. Gerenciamento de sessão 3. Transimissão de dados
  • 52. Sender app: Os passos para o sucesso... 1. Descoberta de dispositivos 2. Gerenciamento de sessão 3. Transimissão de dados
  • 53. Gerenciamento de sessão: Media Router Callback private final MediaRouter.Callback mMediaRouterCallback = new MediaRouter.Callback() { @Override public void onRouteSelected(MediaRouter router, RouteInfo route) { } @Override public void onRouteUnselected(MediaRouter router, RouteInfo route) { } @Override public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo route) { } }
  • 54. Gerenciamento de sessão: Media Router Callback public class MediaRouterPlaybackActivity extends ActionBarActivity { protected void onCreate(Bundle savedInstanceState) { mMediaRouter = MediaRouter.getInstance(this); } public void onStart() { mMediaRouter.addCallback(mSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); } public void onStop() { mMediaRouter.removeCallback(mMediaRouterCallback); super.onStop(); } }
  • 55. Gerenciamento de sessão: Media Router Callback public class MediaRouterPlaybackActivity extends ActionBarActivity { protected void onCreate(Bundle savedInstanceState) { mMediaRouter = MediaRouter.getInstance(this); } public void onStart() { mMediaRouter.addCallback(mSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); } public void onStop() { mMediaRouter.removeCallback(mMediaRouterCallback); super.onStop(); } }
  • 56. Gerenciamento de sessão: Media Router Callback public class MediaRouterPlaybackActivity extends ActionBarActivity { protected void onCreate(Bundle savedInstanceState) { mMediaRouter = MediaRouter.getInstance(this); } public void onStart() { mMediaRouter.addCallback(mSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); } public void onStop() { mMediaRouter.removeCallback(mMediaRouterCallback); super.onStop(); } }
  • 57. Sender app: Os passos para o sucesso... 1. Descoberta de dispositivos 2. Gerenciamento de sessão 3. Transimissão de dados
  • 58. Sender app: Os passos para o sucesso... 1. Descoberta de dispositivos 2. Gerenciamento de sessão 3. Transimissão de dados
  • 59. Sender app: Os passos para o sucesso... 1. Descoberta de dispositivos 2. Gerenciamento de sessão 3. Transimissão de dados
  • 60. Transmissão de dados: Mensagem genérica Cast.CastApi.sendMessage (com.google.android.gms.common.api.GoogleApiClient, NAMESPACE, message) .setResultCallback ( new ResultCallback<Status>() { @Overridepublic void onResult(Status result) { if (!result.isSuccess()) { Log.e(TAG, "Sending message failed"); } } });
  • 61. Transmissão de dados: Remote playback protected void onCreate(Bundle savedInstanceState) { Bundle mediaInfo = new Bundle(); mediaInfo.putString(MediaMetadata.KEY_TITLE, "Big Buck Bunny"); mediaInfo.putString(MediaMetadata.KEY_SUBTITLE, "Blender Foundation"); mediaInfo.putString(MediaMetadata.KEY_STUDIO, "Fusce id nisi turpis. Praesent viverra bibendum semper. Donec tristique, orci"); (...) }
  • 62. Transmissão de dados: Remote playback public void onRouteSelected(MediaRouter router, RouteInfo route) { mRemotePlaybackClient = new RemotePlaybackClient(this, route); mRemotePlaybackClient.play(Uri.parse("http://meu_video.mp4"), "video/mp4", mediaInfo, 0, null, new ItemActionCallback() { @Override public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus, String itemId, MediaItemStatus itemStatus) { logStatus("play: succeeded for item " + itemId); } @Override public void onError(String error, int code, Bundle data) { } }); }
  • 63. Google Cast User Guidelines
  • 64. Google Cast User Guidelines https://developers.google.com/cast/docs/design_checklist#sender
  • 67. CastCompanionLibrary - Registrando receiver app public class CastApplication extends Application { private static VideoCastManager mCastMgr = null; public static VideoCastManager getCastManager(Context context) { if (null == mCastMgr) { mCastMgr = VideoCastManager.initialize(context, APPLICATION_ID, null, null); } mCastMgr.setContext(context); return mCastMgr; } }
  • 68. CastCompanionLibrary - Registrando receiver app public class CastApplication extends Application { private static VideoCastManager mCastMgr = null; public static VideoCastManager getCastManager(Context context) { if (null == mCastMgr) { mCastMgr = VideoCastManager.initialize(context, APPLICATION_ID, null, null); } mCastMgr.setContext(context); return mCastMgr; } } Default Receiver App: CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID
  • 69. Sender app: Descoberta de dispositivos <?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/media_route_menu_item" android:title="@string/media_route_menu_title" app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider" app:showAsAction="always"/></menu>
  • 70. CastCompanionLibrary - Descoberta de devices public class PlayerActivity extends ActionBarActivity { private VideoCastManager mCastManager; private MediaInfo mSelectedMedia; private VideoCastConsumerImpl mCastConsumer; protected void onCreate(Bundle savedInstanceState) { mCastManager = CastApplication.getCastManager(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.main, menu); mCastManager.addMediaRouterButton(menu, R.id.media_route_menu_item); return true; } }
  • 71. CastCompanionLibrary - Gerenciando sessão protected void onCreate(Bundle savedInstanceState) { mCastConsumer = new VideoCastConsumerImpl() { public void onApplicationConnected(ApplicationMetadata appMetadata, String sessionId, boolean wasLaunched) { } public void onApplicationDisconnected(int errorCode) { } public void onDisconnected() { } public void onRemoteMediaPlayerMetadataUpdated() { } public void onFailed(int resourceId, int statusCode) { } public void onConnectionSuspended(int cause) { } public void onConnectivityRecovered() { } }; } protected void onResume() { super.onResume(); mCastManager.addVideoCastConsumer(mCastConsumer); }
  • 72. CastCompanionLibrary - Reproduzindo vídeo remoto protected void onCreate(Bundle savedInstanceState) { Bundle mediaInfo = new Bundle(); mediaInfo.putString(MediaMetadata.KEY_TITLE, "Big Buck Bunny"); mediaInfo.putString(MediaMetadata.KEY_SUBTITLE, "Blender Foundation"); mediaInfo.putString(MediaMetadata.KEY_STUDIO, "Fusce id nisi turpis. Praesent viverra bibendum semper. Donec tristique, orci"); mediaInfo.putString(com.google.sample.castcompanionlibrary.utils.Utils.KEY_URL, http://url.mp4); mediaInfo.putString(com.google.sample.castcompanionlibrary.utils.Utils.KEY_CONTENT_TYPE, "video/mp4"); ArrayList<String> images = new ArrayList<String>(); images.add("http://image_url_480"); images.add("http://image_url_720"); mediaInfo.putStringArrayList(com.google.sample.castcompanionlibrary.utils.Utils.KEY_IMAGES, images); mSelectedMediaInfo = com.google.sample.castcompanionlibrary.utils.Utils.toMediaInfo(mediaInfo); }
  • 73. CastCompanionLibrary - Reproduzindo vídeo remoto mediaInfo.putString(MediaMetadata.KEY_TITLE, "Big Buck Bunny");
  • 74. CastCompanionLibrary - Reproduzindo vídeo remoto mediaInfo.putString(MediaMetadata.KEY_TITLE, "Big Buck Bunny");
  • 75. CastCompanionLibrary - Reproduzindo vídeo remoto mediaInfo.putString(MediaMetadata.KEY_SUBTITLE, "Blender Foundation");
  • 76. CastCompanionLibrary - Reproduzindo vídeo remoto mediaInfo.putString(MediaMetadata.KEY_SUBTITLE, "Blender Foundation");
  • 77. CastCompanionLibrary - Reproduzindo vídeo remoto mediaInfo.putString(MediaMetadata.KEY_STUDIO, "Fusce id nisi turpis. Praesent viverra bibendum semper. Donec tristique, orci");
  • 78. CastCompanionLibrary - Reproduzindo vídeo remoto mediaInfo.putString(MediaMetadata.KEY_STUDIO, "Fusce id nisi turpis. Praesent viverra bibendum semper. Donec tristique, orci");
  • 79. CastCompanionLibrary - Reproduzindo vídeo remoto images.add("http://image_url_480");
  • 80. CastCompanionLibrary - Reproduzindo vídeo remoto images.add("http://image_url_480");
  • 81. CastCompanionLibrary - Reproduzindo vídeo remoto public void onApplicationConnected(ApplicationMetadata appMetadata, String sessionId, boolean wasLaunched) { if (null != mSelectedMedia) { mCastManager.startCastControllerActivity(this, mSelectedMedia, 0, true); finish(); return; } }
  • 87. CCL - CastControllerActivity images.add("http://image_url_720");
  • 88. CCL - CastControllerActivity <activity android:name="com.google.sample.castcompanionlibrary.cast.player.VideoCastControllerActivity" android:launchMode="singleTask" android:screenOrientation="portrait" android:theme="@style/Theme.CastVideoOverlayYellow" > <meta-data android:name="android.support.PARENT_ACTIVITY" android:value="<parentActivity>" /> <intent-filter> <action android:name="android.intent.action.MAIN" /> </intent-filter> </activity>
  • 92. CCL - MiniController <com.google.sample.castcompanionlibrary.widgets.MiniController android:id="@+id/miniController1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:visibility="gone" > </com.google.sample.castcompanionlibrary.widgets.MiniController>
  • 93. CCL - MiniController protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // -- Adding MiniController mMini = (MiniController) findViewById(R.id.miniController1); mCastManager.addMiniController(mMini); } protected void onDestroy() { if (null != mCastManager) { mCastManager.removeMiniController(mMini); } super.onDestroy(); }
  • 95. CCL - OnGoing Notification
  • 96. CCL - OnGoing Notification
  • 97. CCL - OnGoing Notification <receiver android:name="com.google.sample.castcompanionlibrary.remotecontrol.VideoIntentReceiver" > <intent-filter> <action android:name="com.google.sample.castcompanionlibrary.action.toggleplayback" /> <action android:name="com.google.sample.castcompanionlibrary.action.stop" /> </intent-filter> </receiver> <service android:name="com.google.sample.castcompanionlibrary.notification.VideoCastNotificationService" android:exported="false" > <intent-filter> <action android:name="com.google.sample.castcompanionlibrary.action.toggleplayback" /> <action android:name="com.google.sample.castcompanionlibrary.action.stop" /> <action android:name="com.google.sample.castcompanionlibrary.action.notificationvisibility" /> </intent-filter></service>
  • 98. CCL - OnGoing Notification protected void onResume() { mCastManager = CastApplication.getCastManager(this); mCastManager.incrementUiCounter(); } protected void onPause() { mCastManager.decrementUiCounter(); } public class CastApplication extends Application { private static VideoCastManager mCastMgr = null; public static VideoCastManager getCastManager(Context context) { mCastMgr = VideoCastManager.initialize(context, APPLICATION_ID, null, null); mCastMgr.enableFeatures(VideoCastManager.FEATURE_NOTIFICATION ); return mCastMgr; } }
  • 100. CCL - Lock Screen
  • 101. CCL - LockScreen public class CastApplication extends Application { private static VideoCastManager mCastMgr = null; public static VideoCastManager getCastManager(Context context) { mCastMgr = VideoCastManager.initialize(context, APPLICATION_ID, null, null); mCastMgr.enableFeatures(VideoCastManager.FEATURE_NOTIFICATION | VideoCastManager.FEATURE_LOCKSCREEN); return mCastMgr; } }
  • 104. Obrigado! Athila Santos athila@ciandt.com athilahs@gmail.com br.linkedin.com/pub/athila-henrique-dos-santos/ 6/41/744/