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
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; 
} 
}
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

Similar to Integrando sua app Android com Chromecast

Developing for Chromecast on Android
Developing for Chromecast on AndroidDeveloping for Chromecast on Android
Developing for Chromecast on Android
Kurt Mbanje
 
Jollen's Presentation: Introducing Android low-level
Jollen's Presentation: Introducing Android low-levelJollen's Presentation: Introducing Android low-level
Jollen's Presentation: Introducing Android low-level
Jollen Chen
 
Android Froyo
Android FroyoAndroid Froyo
Android Froyo
Robert Cooper
 
What's new in Android P @ I/O Extended Bangkok 2018
What's new in Android P @ I/O Extended Bangkok 2018What's new in Android P @ I/O Extended Bangkok 2018
What's new in Android P @ I/O Extended Bangkok 2018
Somkiat Khitwongwattana
 
Android App Development - 13 Broadcast receivers and app widgets
Android App Development - 13 Broadcast receivers and app widgetsAndroid App Development - 13 Broadcast receivers and app widgets
Android App Development - 13 Broadcast receivers and app widgets
Diego Grancini
 
Android & Beacons
Android & Beacons Android & Beacons
Android & Beacons
Tushar Choudhary
 
What's new in Android O
What's new in Android OWhat's new in Android O
What's new in Android O
Kirill Rozov
 
Synapseindia android application development tutorial
Synapseindia android application development tutorialSynapseindia android application development tutorial
Synapseindia android application development tutorial
Synapseindiappsdevelopment
 
Synapseindia android apps development tutorial
Synapseindia android apps  development tutorialSynapseindia android apps  development tutorial
Synapseindia android apps development tutorial
Synapseindiappsdevelopment
 
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...viWave Study Group - Introduction to Google Android Development - Chapter 23 ...
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...
Ted Chien
 
From newbie to ...
From newbie to ...From newbie to ...
From newbie to ...
Vitali Pekelis
 
Cross-platform mobile apps with Apache Cordova
Cross-platform mobile apps with Apache CordovaCross-platform mobile apps with Apache Cordova
Cross-platform mobile apps with Apache CordovaIvano Malavolta
 
Implementing cast in android
Implementing cast in androidImplementing cast in android
Implementing cast in android
Angelo Rüggeberg
 
BroadcastReceivers in Android
BroadcastReceivers in AndroidBroadcastReceivers in Android
BroadcastReceivers in Android
Perfect APK
 
WebRTC & Firefox OS - presentation at Google
WebRTC & Firefox OS - presentation at GoogleWebRTC & Firefox OS - presentation at Google
WebRTC & Firefox OS - presentation at GoogleRobert Nyman
 
[2015/2016] Apache Cordova APIs
[2015/2016] Apache Cordova APIs[2015/2016] Apache Cordova APIs
[2015/2016] Apache Cordova APIs
Ivano Malavolta
 
Scmad Chapter13
Scmad Chapter13Scmad Chapter13
Scmad Chapter13
Marcel Caraciolo
 
softshake 2014 - Java EE
softshake 2014 - Java EEsoftshake 2014 - Java EE
softshake 2014 - Java EE
Alexis Hassler
 
Android For All The Things
Android For All The ThingsAndroid For All The Things
Android For All The Things
Paul Trebilcox-Ruiz
 

Similar to Integrando sua app Android com Chromecast (20)

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

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
  • 65.
  • 66.
  • 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; } }
  • 102.
  • 104. Obrigado! Athila Santos athila@ciandt.com athilahs@gmail.com br.linkedin.com/pub/athila-henrique-dos-santos/ 6/41/744/