Wednesday, March 13, 2013

Request Permission to access USB accessory

In the post "Hello World ADK: Android code", as mentioned we have not requested permission from user to use USB. If user click Cancel to open HelloADK when plug in, and then start this app manually, it will be stopped.

In this version, myUsbManager.requestPermission() will be called if have no permission for USB. And also implement BroadcastReceiver myUsbPermissionReceiver to handle user action. Such that another dialog will be open to ask user to allow accessing the USB accessory.

Request Permission to access USB accessory
requestPermission() dialog


The MainActivity.java code in Android side
/*
 * manufacturer="Arduino-er"
 * model="HelloADK"
 * version="0.2"
 */

package com.example.helloadk;

import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import com.android.future.usb.UsbAccessory;
import com.android.future.usb.UsbManager;

import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
 
 EditText textOut;
 TextView textIn;
 Button btnSend;
 
 private UsbManager myUsbManager;
 private UsbAccessory myUsbAccessory;
 private ParcelFileDescriptor myParcelFileDescriptor;
 private FileInputStream myFileInputStream;
 private FileOutputStream myFileOutputStream;
 
 private static int RQS_USB_PERMISSION = 0;
 private static final String ACTION_USB_PERMISSION = "com.example.helloadk.usb_permission";
 private PendingIntent PendingIntent_UsbPermission;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  textOut = (EditText)findViewById(R.id.textout);
  textIn = (TextView)findViewById(R.id.textin);
  btnSend = (Button)findViewById(R.id.btnsend);
  
  myUsbManager = UsbManager.getInstance(this);
  IntentFilter intentFilter = new IntentFilter();
  intentFilter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
  registerReceiver(myUsbReceiver, intentFilter);
  
  //Ask USB Permission from user
  Intent intent_UsbPermission = new Intent(ACTION_USB_PERMISSION);
  PendingIntent_UsbPermission = PendingIntent.getBroadcast(
    this,      //context
    RQS_USB_PERMISSION,  //request code
    intent_UsbPermission, //intent 
    0);      //flags
  IntentFilter intentFilter_UsbPermission = new IntentFilter(ACTION_USB_PERMISSION);
  registerReceiver(myUsbPermissionReceiver, intentFilter_UsbPermission);
  
  btnSend.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    
    String textToSend = textOut.getEditableText().toString();
    if(!textToSend.equals("")){
     sendText(textToSend);
    }
   }
  });
  
 }

 @Override
 protected void onResume() {
  super.onResume();
  
  if(myFileInputStream == null || myFileOutputStream == null){
   
   UsbAccessory[] usbAccessoryList = myUsbManager.getAccessoryList();
   UsbAccessory usbAccessory = null;
   if(usbAccessoryList != null){
    usbAccessory = usbAccessoryList[0];
    
    if(usbAccessory != null){
     if(myUsbManager.hasPermission(usbAccessory)){
      //already have permission
      OpenUsbAccessory(usbAccessory);
     }else{
      //request permission
      Toast.makeText(MainActivity.this, 
        "ask for permission", 
        Toast.LENGTH_LONG).show();
      
      synchronized(myUsbReceiver){
       myUsbManager.requestPermission(usbAccessory, 
         PendingIntent_UsbPermission);
      }
     }
    }
   }
  }
 }
 
 Runnable myRunnable = new Runnable(){

  @Override
  public void run() {
   int numberOfByteRead = 0;
   byte[] buffer = new byte[255];
   
   while(numberOfByteRead >= 0){
    
    try {
     numberOfByteRead = myFileInputStream.read(buffer, 0, buffer.length);
     final StringBuilder stringBuilder = new StringBuilder();
     for(int i=0; i<numberOfByteRead; i++){
      stringBuilder.append((char)buffer[i]);
     }
     
     runOnUiThread(new Runnable(){

      @Override
      public void run() {
       textIn.setText(stringBuilder.toString());
      }});
     
     
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     break;
    }
   }
  }
  
 };
 
 private void OpenUsbAccessory(UsbAccessory acc){
  myParcelFileDescriptor = myUsbManager.openAccessory(acc);
  if(myParcelFileDescriptor != null){
   
   myUsbAccessory = acc;
   FileDescriptor fileDescriptor = myParcelFileDescriptor.getFileDescriptor();
   myFileInputStream = new FileInputStream(fileDescriptor);
   myFileOutputStream = new FileOutputStream(fileDescriptor);
   
   Thread thread = new Thread(myRunnable);
   thread.start();
  }
 }
 
 private void closeUsbAccessory(){
  
  if(myParcelFileDescriptor != null){
   try {
    myParcelFileDescriptor.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
  
  myParcelFileDescriptor = null;
  myUsbAccessory = null;
 }

 @Override
 protected void onPause() {
  super.onPause();
  closeUsbAccessory();
 }

 @Override
 protected void onDestroy() {
  super.onDestroy();
  unregisterReceiver(myUsbReceiver);
  unregisterReceiver(myUsbPermissionReceiver);
 }
 
 private BroadcastReceiver myUsbReceiver = new BroadcastReceiver(){
  
  @Override
  public void onReceive(Context context, Intent intent) {

   String action = intent.getAction();
   if(action.equals(UsbManager.ACTION_USB_ACCESSORY_DETACHED)){
    
    Toast.makeText(MainActivity.this, 
      "onReceive: ACTION_USB_ACCESSORY_DETACHED", 
      Toast.LENGTH_LONG).show();
    
    UsbAccessory usbAccessory = UsbManager.getAccessory(intent);
    
    if(usbAccessory!=null && usbAccessory.equals(myUsbAccessory)){
     closeUsbAccessory();
    }
   }
  }
 };
 
 private BroadcastReceiver myUsbPermissionReceiver = new BroadcastReceiver(){

  @Override
  public void onReceive(Context context, Intent intent) {
   String action = intent.getAction();
   if(action.equals(ACTION_USB_PERMISSION)){

    synchronized(this){
     UsbAccessory usbAccessory = UsbManager.getAccessory(intent);
     
     if(intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)){
      OpenUsbAccessory(usbAccessory);
      
      Toast.makeText(MainActivity.this, 
        "ACTION_USB_PERMISSION accepted", 
        Toast.LENGTH_LONG).show();
     }else{
      Toast.makeText(MainActivity.this, 
        "ACTION_USB_PERMISSION rejected", 
        Toast.LENGTH_LONG).show();
      finish();
     }
    }
   }
  }
  
 };

 private void sendText(String text){

  byte[] buffer = text.getBytes();

  if(myFileOutputStream != null){
   
   try {
    myFileOutputStream.write(buffer);
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } 
  }
 }

}

Update version="0.2" in /res/xml/myfilter.xml.
<?xml version="1.0" encoding="UTF-8"?>
<resources>
    <usb-accessory
        manufacturer="Arduino-er"
        model="HelloADK"
        version="0.2"/>
</resources>


AndroidManifest.xml and the layout file keep no change as in the post "Hello World ADK: Android code".


Modify the code in Arduino side to update versionNumber and download url.
#include "variant.h"
#include <stdio.h>
#include <adk.h>


// Accessory descriptor. It's how Arduino identifies itself to Android.
char applicationName[] = "HelloADK"; // the app on your phone
char accessoryName[] = "Arduino Due"; // your Arduino board
char companyName[] = "Arduino-er";

// Make up anything you want for these
char versionNumber[] = "0.2";
char serialNumber[] = "1";
char url[] = "https://sites.google.com/site/arduinosite/exercise/helloadk/HelloADK_0.2.apk";

USBHost Usb;
ADK adk(&Usb, companyName, applicationName, accessoryName,versionNumber,url,serialNumber);

// Pin 13 has an LED connected on most Arduino boards.
int led = 13;

void setup() {
    Serial.begin(9600);
    cpu_irq_enable();
  
    pinMode(led, OUTPUT);
    //Indicate start of program
    digitalWrite(led, LOW);
    delay(2000);
    digitalWrite(led, HIGH);
    for(int i = 0; i <= 2; i++){
        digitalWrite(led, HIGH);
        delay(250);
        digitalWrite(led, LOW);
        delay(250);
    }
}

#define RCVSIZE 128

void loop() {
  
    char helloworld[] = "Hello World!\r\n";
  
    uint8_t buf[RCVSIZE];
    uint32_t nbread = 0;
  
    Usb.Task();
    
    if (adk.isReady()){
        digitalWrite(led, HIGH);
        
        adk.read(&nbread, RCVSIZE, buf);
        if (nbread > 0){
            adk.write(nbread, buf);
        }
        
    }else{
        digitalWrite(led, LOW);
    }
    
}


Next:
- Improved Hello World ADK


1 comment:

  1. http://sites.google.com/site/arduinosite/exercise/helloadk-android-code/HelloADK_20130314a.zip

    ReplyDelete