Friday, October 5, 2018

Alternative Input Methods For Android Tv

Posted past times Benjamin Baxter, Developer Advocate together with Bacon Connoisseur

 Developer Advocate together with Bacon Connoisseur Alternative input methods for Android TV

All TVs cause got the same work alongside keyboard input: It is real cumbersome to hunt together with peck for each alphabetic lineament using a D-pad alongside a remote. And if you lot brand a mistake, trying to right it compounds the problem.

APIs similar Smart Lock together with Autofill, tin repose user's frustrations, simply for certainly types of input, similar login, you lot demand to collect complex input that is hard for users using the on-screen keyboard.

With the Nearby Connections API, you lot tin purpose a instant concealment to get together input from the user alongside less friction.

How Nearby Connections works

From the documentation:

"Nearby Connections is an offline peer-to-peer socket model for communication based on advertising together with discovering devices inward proximity.

Usage of the API falls into 2 phases: pre-connection, together with post-connection.

In the pre-connection phase, Advertisers advertise themselves, field Discoverers regain nearby Advertisers together with transportation connexion requests. Influenza A virus subtype H5N1 connexion asking from a Discoverer to an Advertiser initiates a symmetric authentication catamenia that results inward both sides independently accepting (or rejecting) the connexion request.

After a connexion asking is accepted past times both sides, the connexion is established together with the devices come inward the post-connection phase, during which both sides tin telephone substitution data."

In most cases the TV is the advertiser together with the telephone is the discoverer. In the representative below, the assumed instant device is a phone. The API together with patterns described inward this article are non express to a phone. For example, a tablet could likewise hold upward the instant concealment device.

 Developer Advocate together with Bacon Connoisseur Alternative input methods for Android TV

Login Example

There are many times when keyboard input is required. Authenticating users together with collecting billing information (like zip codes together with call on card) are mutual cases. This representative handles a login catamenia that uses a instant concealment to encounter how Nearby Connections tin assistance cut down friction.

1. The user opens your app on her TV together with needs to login. You tin demo a concealment of options similar to the setup catamenia for a novel TV.

 Developer Advocate together with Bacon Connoisseur Alternative input methods for Android TV

2. After the user chooses to login alongside their phone, the TV should outset advertising together with transportation the user to the associated login app on their phone, which should outset discovering.

There are a multifariousness of solutions to opened upward the app on the phone. As an example, Android TV's setup catamenia has the user opened upward the corresponding app on their mobile device. Initiating the hand-off is a to a greater extent than a UX occupation concern than a technology concern.

 Developer Advocate together with Bacon Connoisseur Alternative input methods for Android TV

3. The telephone app should display the advertising TV together with prompt the user to initiate the connection. After the (encrypted -- encounter Security Considerations below for to a greater extent than on this) connexion is established the TV tin halt advertising together with the telephone tin halt discovering.

"Advertising/Discovery using Nearby Connections for hours on halt tin impact a device's battery. While this is non commonly an number for a plugged-in TV, it tin hold upward for mobile devices, thus hold upward witting virtually stopping advertising together with uncovering i time they're no longer needed."

4. Next, the telephone tin outset collecting the user's input. Once the user enters their login information, the telephone should transportation it to the TV inward a BYTES payload over the secure connection.

5. When the TV receives the message it should transportation an ACK (using a BYTES payload) dorsum to the telephone to confirm delivery.

6. When the telephone receives the ACK, it tin safely close the connection.

The next diagram summarizes the sequence of events:

 Developer Advocate together with Bacon Connoisseur Alternative input methods for Android TV

UX considerations

Nearby Connections needs place permissions to hold upward able to regain nearby devices. Be transparent alongside your users. Tell them why they demand to grant the place permission on their phone.

Since the TV is advertising, it does non demand place permissions.

Start advertising: The TV code

After the user chooses to login on the phone, the TV should outset advertising. This is a real uncomplicated procedure alongside the Nearby API.

override fun onGuidedActionClicked(action: GuidedAction?) {     super.onGuidedActionClicked(action)     if( activity == loginAction ) {         // Update the UI thus the user knows to banking concern check their telephone         navigationFlowCallback.navigateToConnectionDialog()         doStartAdvertising(requireContext()) { payload ->             handlePayload(payload)         }     } } 

When the user clicks a button, update the UI to tell them to await at their telephone to continue. Be certainly to offering a means to cancel the remote login together with endeavour manually alongside the cumbersome onscreen keyboard.

This representative uses a GuidedStepFragment simply the same UX pattern applies to whatever blueprint you lot choose.

Advertising is straightforward. You demand to render a name, a service id (typically the bundle name), together with a `ConnectionLifeCycleCallback`.

You likewise demand to choose a strategy that both the TV together with the telephone use. Since it is possible that the users has multiple TVs (living room, bedroom, etc) the best strategy to purpose is P2P_CLUSTER.

Then outset advertising. The onSuccessListener together with onFailureListener tell you lot whether or non the device was able to outset advertising, they practise non betoken a device has been discovered.

 fun doStartAdvertising(context: Context) {     Nearby.getConnectionsClient(context).startAdvertising(         context.getString(R.string.tv_name),         context.packageName,         connectionLifecycleCallback,         AdvertisingOptions.Builder().setStrategy(Strategy.P2P_CLUSTER).build()     )     .addOnSuccessListener {         Log.d(LoginStepFragment.TAG, "We are advertising!")     }     .addOnFailureListener {         Log.d(LoginStepFragment.TAG, "We cannot outset advertising.")         Toast.makeText(             context, "We cannot outset advertising.", Toast.LENGTH_LONG)                 .show()     } }  

The existent magic happens inward the `connectionLifecycleCallback` that is triggered when devices outset to initiate a connection. The TV should convey the handshake from the telephone (after performing the necessary authentication -- encounter Security Considerations below for more) together with render a payload listener.

 val connectionLifecycleCallback = object : ConnectionLifecycleCallback() {      override fun onConnectionInitiated(             endpointId: String,              connectionInfo: ConnectionInfo     ) {         Log.d(TAG, "Connection initialized to endpoint: $endpointId")         // Make certainly to authenticate using `connectionInfo.authenticationToken`          // earlier accepting         Nearby.getConnectionsClient(context)             .acceptConnection(endpointId, payloadCallback)     }      override fun onConnectionResult(         endpointId: String,          connectionResolution: ConnectionResolution     ) {         Log.d(TAG, "Received number from connection: ${connectionResolution.status.statusCode}")         doStopAdvertising()         when (connectionResolution.status.statusCode) {             ConnectionsStatusCodes.STATUS_OK -> {                 Log.d(TAG, "Connected to endpoint: $endpointId")                 otherDeviceEndpointId = endpointId             }             else -> {                 otherDeviceEndpointId = aught             }         }     }      override fun onDisconnected(endpointId: String) {         Log.d(TAG, "Disconnected from endpoint: $endpointId")         otherDeviceEndpointId = aught     } }  

The payloadCallback listens for the telephone to transportation the login information needed. After receiving the login information, the connexion is no longer needed. We larn into to a greater extent than item afterward inward the Ending the Conversation section.

Discovering the big screen: The telephone code

Nearby Connections does non require the user's consent. However, the place permission must hold upward granted inward club for uncovering alongside Nearby Connections to function its magic. (It uses BLE scanning nether the covers.)

After opening the app on the phone, outset past times prompting the user for place permission if non already granted on devices running Marshmallow together with higher.

Once the permission is granted, outset discovering, confirm the connection, collect the credentials, together with transportation a message to the TV app.

Discovering is equally uncomplicated equally advertising. You demand a service id (typically the bundle call -- this should hold upward the same on the Discoverer together with Advertiser for them to encounter each other), a name, together with a `EndpointDiscoveryCallback`. Similar to the TV code, the catamenia is triggered past times callbacks based on the connexion status.

 Nearby.getConnectionsClient(context).startDiscovery(         context.packageName,         mobileEndpointDiscoveryCallback,         DiscoveryOptions.Builder().setStrategy(Strategy.P2P_CLUSTER).build()         )         .addOnSuccessListener {             // We're discovering!             Log.d(TAG, "We are discovering!")         }          .addOnFailureListener {             // We were unable to outset discovering.             Log.d(TAG, "We cannot outset discovering!")         }  

The Discoverer's listeners are similar to the Advertiser's success together with failure listeners; they signal if the asking to outset uncovering was successful or not.

Once you lot regain an advertiser, the `EndpointDiscoveryCallback` is triggered. You demand to maintain rail of the other endpoint to know who to transportation the payload, e.g.: the user's credentials, to later.

 val mobileEndpointDiscoveryCallback = object : EndpointDiscoveryCallback() {     override fun onEndpointFound(         endpointId: String,          discoveredEndpointInfo: DiscoveredEndpointInfo     ) {         // An endpoint was found!         Log.d(TAG, "An endpoint was found, ${discoveredEndpointInfo.endpointName}")         Nearby.getConnectionsClient(context)             .requestConnection(                 context.getString(R.string.phone_name),                  endpointId,                  connectionLifecycleCallback)     }      override fun onEndpointLost(endpointId: String) {         // Influenza A virus subtype H5N1 previously discovered endpoint has gone away.         Log.d(TAG, "An endpoint was lost, $endpointId")     } } 

One of the devices must initiate the connection. Since the Discoverer has a callback for endpoint discovery, it makes feel for the telephone to asking the connexion to the TV.

The telephone asks for a connexion supplying a `connectionLifecycleCallback` which is symmetric to the callback inward the TV code.

 val connectionLifecycleCallback = object : ConnectionLifecycleCallback() {     override fun onConnectionInitiated(         endpointId: String,         connectionInfo: ConnectionInfo     ) {         Log.d(TAG, "Connection initialized to endpoint: $endpointId")         // Make certainly to authenticate using `connectionInfo.authenticationToken` earlier accepting         Nearby.getConnectionsClient(context)                 .acceptConnection(endpointId, payloadCallback)     }      override fun onConnectionResult(         endpointId: String,         connectionResolution: ConnectionResolution     ) {         Log.d(TAG, "Connection number from endpoint: $endpointId")         when (connectionResolution.status.statusCode) {             ConnectionsStatusCodes.STATUS_OK -> {                 Log.d(TAG, "Connected to endpoint: $endpointId")                 otherDeviceEndpointId = endpointId                 waitingIndicator.visibility = View.GONE                 emailInput.editText?.isEnabled = truthful                 passwordInput.editText?.isEnabled = truthful                  Nearby.getConnectionsClient(this).stopDiscovery()             }             else -> {                 otherDeviceEndpointId = aught             }         }     }      override fun onDisconnected(endpointId: String) {         Log.d(TAG, "Disconnected from endpoint: $endpointId")         otherDeviceEndpointId = aught     } }  

Once the connexion is established, halt uncovering to avoid keeping this battery-intensive performance running longer than needed. The representative stops uncovering after the connexion is established, simply it is possible for a user to go out the activity earlier that happens. Be certainly to halt the discovery/advertising inward onStop() on both the TV together with phone.


 override fun onStop() {     super.onStop()     Nearby.getConnectionsClient(this).stopDiscovery() } 


Just similar a TV app, when you lot convey the connexion you lot render a payload callback. The callback listens for messages from the TV app such equally the ACK described inward a higher house to create clean upward the connection.

After the devices are connected, the user tin purpose the keyboard together with transportation their authentication information to the TV past times calling `sendPayload()`.

 fun sendCreditials() {      val electronic mail = emailInput.editText?.text.toString()     val password = passwordInput.editText?.text.toString()      val creds = "$email:$password"     val payload = Payload.fromBytes(creds.toByteArray())     Log.d(TAG, "sending payload: $creds")     if (otherDeviceEndpointId != null) {         Nearby.getConnectionsClient(this)                 .sendPayload(otherDeviceEndpointId, payload)     } } 

Ending the conversation

After the telephone sends the payload to the TV (and the login is successful), at that spot is no argue for the devices to stay connected. The TV tin initiate the disconnection alongside a uncomplicated shutdown protocol.

The TV should transportation an ACK to the telephone after it receives the credential payload.

 val payloadCallback = object : PayloadCallback() {     override fun onPayloadReceived(endpointId: String, payload: Payload) {         if (payload.type == Payload.Type.BYTES) {             payload.asBytes()?.let {                 val torso = String(it)                 Log.d(TAG, "A payload was received: $body")                 // Validate that this payload contains the login credentials, together with procedure them.                  val ack = Payload.fromBytes(ACK_PAYLOAD.toByteArray())                 Nearby.getConnectionsClient(context).sendPayload(endpointId, ack)             }         }     }      override fun onPayloadTransferUpdate(         endpointId: String,         update: PayloadTransferUpdate     ) {    } }  

The telephone should cause got a `PayloadCallback` that initiates a disconnection inward answer to the ACK. This is likewise a proficient fourth dimension to reset the UI to demo an authenticated state.

 somebody val payloadCallback = object : PayloadCallback() {     override fun onPayloadReceived(endpointId: String, payload: Payload) {         if (payload.type == Payload.Type.BYTES) {             payload.asBytes()?.let {                 val torso = String(it)                 Log.d(TAG, "A payload was received: $body")                  if (body == ACK_PAYLOAD) {                     waitingIndicator.visibility = View.VISIBLE                     waitingIndicator.text = getString(R.string.login_successful)                     emailInput.editText?.isEnabled = imitation                     passwordInput.editText?.isEnabled = imitation                     loginButton.isEnabled = imitation                      Nearby.getConnectionsClient(this@MainActivity)                         .disconnectFromEndpoint(endpointId)                 }             }         }     }      override fun onPayloadTransferUpdate(         endpointId: String,         update: PayloadTransferUpdate     ) {    } } 

Security considerations

For safety (especially since we're sending over sensitive information similar login credentials), it's strongly recommended that you lot authenticate the connexion past times showing a code together with having the user confirm that the 2 devices existence connected are the intended ones -- without this, the connexion established past times Nearby Connection is encrypted simply non authenticated, together with that's susceptible to Man-In-The-Middle attacks. The documentation goes into greater item on how to authenticate a connection.

 Developer Advocate together with Bacon Connoisseur Alternative input methods for Android TV

Does your app offering a instant concealment experience?

There are many times when a user needs to render input to a TV app. The Nearby API provides a means to offload the hardships of an onscreen-dpad-driven keyboard to an slow together with familiar telephone keyboard.

What purpose cases practise you lot cause got where a instant concealment would simplify your user's life? Leave a comment or transportation me (@benjamintravels) or Varun (@varunkapoor, Team Lead for Nearby Connections) a tweet to maintain the discussion.

Related Post

Alternative Input Methods For Android Tv
4/ 5
Oleh