Upload
paul-trebilcox-ruiz
View
568
Download
0
Embed Size (px)
Citation preview
Android For All The Things
Paul Ruiz
New Android Form Factors
• Android Wear• Android TV• Android Auto
Android Wear
Android for wearable computing (smart watches)
Design for Accessibility Notifications Hardware Sensors Device Communication
Design for Accessibility
Glanceable Information Voice Actions No to Low Interactions
Notifications
Cards● Action Buttons● Quick Reply● Media Controls
Notifications
NotificationsAction Button Notifications://Create action pending intentIntent intent = new Intent( Intent.ACTION_VIEW );intent.setData( Uri.parse( "http://ptrprograms.blogspot.com" ) );PendingIntent pendingIntent = PendingIntent.getActivity( getActivity(), 0, intent, 0 );
//Create notification builder with NotificationCompatNotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder( getActivity() )
.setSmallIcon( R.drawable.ic_launcher )
.setLargeIcon( BitmapFactory.decodeResource( getResources(), R.drawable.icon ) )
.setContentText( getString( R.string.content_text ) )
.setContentTitle( getString( R.string.content_title ) )
.addAction( R.drawable.ic_launcher, "Launch Blog", pendingIntent );
//Create WearableNotification with the previous builder as a baseNotification notification = new WearableNotifications.Builder( notificationBuilder ) .setHintHideIcon( true )
.build();
mNotificationManager.notify( notificationId, notification );
NotificationsQuick Reply Notifications://Create notification builder with NotificationCompatNotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder( getActivity() )
.setSmallIcon( R.drawable.ic_launcher )
.setLargeIcon( BitmapFactory.decodeResource( getResources(), R.drawable.icon ) )
.setContentText( getString( R.string.content_text ) )
.setContentTitle( getString( R.string.content_title ) )
//Create RemoteInput list of quick reply optionsRemoteInput remoteInput = new RemoteInput.Builder( "extra_replies" )
.setLabel( ''Transportation'' )
.setChoices( getResources().getStringArray( R.array.getting_around ) )
.build();
Notification notification =new WearableNotifications.Builder( notificationBuilder )
.setHintHideIcon( true )
.addRemoteInputForContentIntent( remoteInput )
.build();
mNotificationManager.notify( notificationId, notification );
Hardware Sensors Gyroscope Compass Barometer Optical Heart Rate Monitor Accelerometer
Hardware SensorsRegister the SensorListener from android.sensor package:
public void start( SensorManager manager ) { this.mSensorManager = manager;
//Check if device has a heart rate sensor mHeartRateSensor = mSensorManager .getDefaultSensor( Sensor.TYPE_HEART_RATE );
//If heart rate sensor exists, associate it with the SensorListener if ( mHeartRateSensor != null ) { mSensorManager.registerListener( this, mHeartRateSensor, SensorManager.SENSOR_DELAY_FASTEST ); }}
Hardware SensorsImplement SensorEventListener:
@Overridepublic void onSensorChanged( SensorEvent event ) { if ( event.sensor.getType() == Sensor.TYPE_HEART_RATE ) { if ( (int) event.values[0] > 0 ) { handleHeartRate( (int) event.values[0] ); } }}
Device Communication
Direct Bluetooth Wear APIs
− Message and DataLayer APIs – Play Services
Device Communication private void sendMessage( final String path, final String text ) { new Thread( new Runnable() { @Override public void run() {
//Get all nodes connected to the phone NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes( mApiClient ).await();
//Try sending a message to each node via the Wearable Message API for( Node node : nodes.getNodes() ) { Wearable.MessageApi.sendMessage( mApiClient, node.getId(), path, text.getBytes() ).await(); } } } ).start(); }
Device Communication
Implement MessageApi.MessageListener or Extend WearableListenerService
@Override public void onMessageReceived( MessageEvent messageEvent ) { if( messageEvent.getPath().equalsIgnoreCase( ''/PathFilter'' ) ) { handleMessageEvent( messageEvent.getData() ); } else { super.onMessageReceived( messageEvent ); } }
Additional Resources for WearAndroid Developers Documentation:
https://developer.android.com/wear/index.htmlDesigning for Wearables
https://www.youtube.com/watch?v=ea_KCJ2qy6sBuilding for Android Wear: Depth and Flexibility
http://android-developers.blogspot.com/2015/02/building-for-android-wear-depth-and.html
Related TutorialsBuilding a Native Wear Application
http://bit.ly/1B8yfL8
Wear Notifications
http://bit.ly/1FgomIu
Using Native Android Sensors
http://bit.ly/1Azfe0U
Wear Message API
http://bit.ly/1D0v56V
Sample Code Projects for WearAndroid Wear Seizure Detector
https://github.com/PaulTR/WearHackathon
Wear MessageAPI
https://github.com/PaulTR/AndroidDemoProjects/tree/ master/WearMessageApi
Native App – Stay Awake
https://github.com/PaulTR/AndroidDemoProjects/ tree/master/StayAwake
Android TV
Designing for the Livingroom Media Apps Games
Designing for the Livingroom
10 Foot View Immersive Experiences Voice Interaction Audio Feedback Provide Recommendations
Media Apps Leanback Support Library
− Browse Fragment Horizontal and Vertical Navigation Fastlane Navigation Similar to ListFragment
− DetailFragment Detailed information and action chooser Recommendations
− SearchFragment Content Activity
BrowseFragment
BrowseFragment Rows private void loadRows() {
ArrayObjectAdapter rowsAdapter = new ArrayObjectAdapter( new ListRowPresenter() ); CardPresenter cardPresenter = new CardPresenter();
for( String category : getCategories() ) { ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter( cardPresenter ); for( Movie movie : mMovies ) {
//Group movies by their category if( category.equalsIgnoreCase( movie.getCategory() ) ) listRowAdapter.add( movie ); }
//Add headers for BrowseFragment Categories if( listRowAdapter.size() > 0 ) { HeaderItem header = new HeaderItem( rowsAdapter.size() - 1, category, null ); rowsAdapter.add( new ListRow( header, listRowAdapter ) ); } }
setAdapter( rowsAdapter );
}
DetailFragment
DetailFragmentUse an AsyncTask to load DetailFragment:
@Overrideprotected DetailsOverviewRow doInBackground( Movie... movies ) { //Create the initial details 'row' DetailsOverviewRow row = new DetailsOverviewRow( mSelectedMovie );
//Set main image for details Bitmap poster = getPosterForMovie( mSelectedMovie ); row.setImageBitmap( getActivity(), poster );
//Add buttons to detail view row.addAction( new Action( ACTION_WATCH, getResources().getString( R.string.watch ), getResources().getString( R.string.watch_subtext) ) );
return row;}
DetailFragment@Overrideprotected void onPostExecute( DetailsOverviewRow detailRow ) { ClassPresenterSelector classPresenter = new ClassPresenterSelector();
/* Get the presenter for the detail information: 1. Uses the binder pattern to associate movie dana to the detail view 2. Sets background color and styles 3. Adds ActionClickedListeners to Action buttons */ classPresenter.addClassPresenter( DetailsOverviewRow.class, getDetailsOverviewRowPresenter() );
//Create the recommendations row classPresenter.addClassPresenter( ListRow.class, new ListRowPresenter() );
//Put everything together ArrayObjectAdapter adapter = new ArrayObjectAdapter( classPresenter ); adapter.add( detailRow ); loadRelatedMedia( adapter ); setAdapter( adapter );}
DetailFragment - Recommendations
DetailFragment - Recommendationsprivate void loadRelatedMedia( ArrayObjectAdapter adapter ) {
List<Movie> movies = getMovies(); List<Movie> related = new ArrayList<>();
//Save a list of 'related' movies. In this case, all from the same category for( Movie movie : movies ) { if( movie.getCategory().equals( mSelectedMovie.getCategory() ) ) { related.add( movie ); } }
//Create a new row adapter for related movies using the same movie cards in BrowseFragment ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter( new CardPresenter() ); for( Movie movie : related ) { listRowAdapter.add( movie ); }
//Create a new header and associate the related row with the //detail view adapter HeaderItem header = new HeaderItem( 0, "Related", null ); adapter.add( new ListRow( header, listRowAdapter ) );}
Games Design– Landscape
– Companion Apps
Game Controller
Game Controller
Game ControllerImplement InputDeviceListener
public boolean handleMotionEvent(MotionEvent motionEvent) { Int deviceId = motionEvent.getDeviceId(); float leftJoystickX = motionEvent.getAxisValue( MotionEvent.AXIS_X );
float leftJoystickY = motionEvent.getAxisValue( MotionEvent.AXIS_Y ); float rightJoystickX = motionEvent.getAxisValue( MotionEvent.AXIS_Z ); float rightJoystickY = motionEvent.getAxisValue( MotionEvent.AXIS_RZ ); return true; }
public boolean handleKeyEvent(KeyEvent keyEvent) {Int deviceId = keyEvent.getDeviceId();
return keyEvent.getKeyCode() == KeyEvent.KEYCODE_BUTTON_X;/* Possible KeyEvents: KEYCODE_BUTTON_A, KEYCODE_BUTTON_B, KEYCODE_BUTTON_X, KEYCODE_BUTTON_YKEYCODE_BUTTON_R1, KEYCODE_BUTTON_R2,KEYCODE_BUTTON_L1, KEYCODE_BUTTON_L2, etc */
}
Additional Resources for TVAndroid Developers Documentation:
http://developer.android.com/training/tv/index.html
Android Design Documentation: http://developer.android.com/design/tv/index.html
Related TutorialsCreating a Media App for Android TV:
http://bit.ly/1D9gwAL
Getting Started with the Gamepad Controller for Android TV: http://bit.ly/1MMjPDn
Sample Code Projects for Android TV
Android TV Media Player https://github.com/PaulTR/AndroidDemoProjects/ tree/master/AndroidTVMediaPlayer
Game Using Game Controller https://github.com/PaulTR/AndroidDemoProjects/ tree/master/AndroidTVAsteroidBelt
Android Auto Design
− Glanceable and Simple− Context Aware− Provided UIs
Implementation− CarExtender Notifications− Media Browser Interface – Folders and playable
items, MediaSession callbacks
Out Soon
Message Cards
Auto Messaging App//Create UnreadConversation ObjectNotificationCompat.CarExtender.UnreadConversation.Builder unreadConversationBuilder = new NotificationCompat.CarExtender.UnreadConversation.Builder( ''Convo'' ); unreadConversationBuilder.setReadPendingIntent( getMessageReadPendingIntent() ); unreadConversationBuilder.setReplyAction( getMessageReplyPendingIntent(), getVoiceReplyRemoteInput() );
unreadConversationBuilder.addMessage( "Message Text" );
return unreadConversationBuilder.build()
Auto Messaging App//Create Notification with Unread ConversationNotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder( getApplicationContext() ) .setSmallIcon( R.drawable.ic_launcher ) .setLargeIcon( BitmapFactory.decodeResource( getResources(), R.drawable.ic_launcher ) ) .setContentText( "content text" ) .setWhen( Calendar.getInstance().get( Calendar.SECOND ) ) .setContentTitle( "content title" );
notificationBuilder.extend( new NotificationCompat.CarExtender() .setUnreadConversation( getUnreadConversation() ) );NotificationManagerCompat.from( this ).notify( 1, notificationBuilder.build() );
Auto Media App
Auto Media App
Auto Media App@Overridepublic void onLoadChildren(String parentId, Result<List<MediaBrowser.MediaItem>> result) { //This method is called by the system to populate items in the media browser List<MediaBrowser.MediaItem> items = getMediaItemsById( parentId ); if( items != null ) result.sendResult( items );}
private List<MediaBrowser.MediaItem> getMediaItemsById( String id ) { List<MediaBrowser.MediaItem> mediaItems = new ArrayList<>(); if( BROWSEABLE_ROOT.equalsIgnoreCase( id ) ) { //Add folders here mediaItems.add( generateBrowseableMediaItemByGenre ( BROWSEABLE_ROCK ) ); } else //Get media items for the selected folder return getPlayableMediaItemsByGenre( id );
return mediaItems;}
Auto Media Appprivate MediaBrowser.MediaItem generateBrowseableMediaItemByGenre( String genre ) { MediaDescription.Builder mediaDescriptionBuilder = new MediaDescription.Builder(); mediaDescriptionBuilder.setMediaId( genre ); mediaDescriptionBuilder.setTitle( genre ); mediaDescriptionBuilder.setIconBitmap( folderBitmap );
return new MediaBrowser.MediaItem( mediaDescriptionBuilder.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE );}
private MediaBrowser.MediaItem generatePlayableMediaItem( Song song ) { MediaDescription.Builder mediaDescriptionBuilder = new MediaDescription.Builder(); mediaDescriptionBuilder.setMediaId( song.getuId() ); mediaDescriptionBuilder.setTitle( song.getTitle() ); mediaDescriptionBuilder.setSubtitle( song.getArtist() ); mediaDescriptionBuilder.setIconUri( song.getImage() ) );
return new MediaBrowser.MediaItem( mediaDescriptionBuilder.build(), MediaBrowser.MediaItem.FLAG_PLAYABLE );}
Additonal Resources for Auto
Developer Overview: https://developer.android.com/auto/overview.html
Managing Audio Playback: https://developer.android.com/training/managing-audio/index.html
Notifications: http://developer.android.com/guide/topics/ui/notifiers/ notifications.html
Related TutorialsUsing the Android Auto Media Browser: http://bit.ly/17KsqWj
Sending Messages to Android Auto: http://bit.ly/1JB9ZoT
Sample Code Projects for Auto
Media Browser: https://github.com/PaulTR/AndroidDemoProjects/tree/ master/AndroidAutoMedia
Auto Messenger: https://github.com/PaulTR/AndroidDemoProjects/tree/ master/AndroidAutoMessenger
Me
Android Development Blog:
http://ptrprograms.blogspot.com/
GitHub:
https://github.com/PaulTR
Google Plus:
+PaulTrebilcoxRuiz