Conhecendo o Android NDK: integrando código nativo às suas aplicações Android
Integrando sua app Android com Chromecast
-
Upload
athila-henrique-dos-santos -
Category
Mobile
-
view
238 -
download
0
description
Transcript of Integrando sua app Android com Chromecast
Integrando sua app Android com Chromecast
Athila [email protected]
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
ControleComando 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
● Sender app
Chromecast: Requisitos
● Sender app
Chromecast: Requisitos
● Receiver app
● Sender app
Chromecast: Requisitos
● Receiver app
● Sender app
Chromecast: Requisitos
● Receiver app
Default Receiver (pronto para uso)
● Sender app
Chromecast: Requisitos
Styled Media Receiver
● Receiver app
Default Receiver (pronto para uso)
Custom Receiver
● Sender app
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Chromecast: Requisitos
Styled Media Receiver
● Receiver app
Default Receiver (pronto para uso)
Custom Receiver
● Sender app
Chromecast: Requisitos
Styled Media Receiver
● Receiver app
Default Receiver (pronto para uso)
Custom Receiver
● Sender app
Chromecast: Requisitos
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
<?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>
Sender app: Descoberta de dispositivos
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
<?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>
Sender app: Descoberta de dispositivos
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ãoprotected 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); }
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
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 Notificationprotected 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 [email protected]@gmail.com
br.linkedin.com/pub/athila-henrique-dos-santos/6/41/744/