Friday, September 12, 2014

Adding Navigation Drawer to Android Project

When attempting to add a navigation drawer to my application, I found that the templates used by Android Studio caused a crash. I am not sure what caused this crash, but I got very tired of attempting to debug boilerplate code. Instead, I followed the "Creating a Navigation Drawer" Tutorial on HMKCode (http://hmkcode.com/android-creating-a-navigation-drawer/), I found this tutorial to be the most helpful one available. And the result actually worked.

What this tutorial missed, I found in the "Navigation Drawer Android Example" (http://javatechig.com/android/navigation-drawer-android-example#33-handle-navigation-click-events).  


1) The ability to load a fragment:

// Creating a fragment object
WebViewFragment rFragment = new WebViewFragment();

// Passing selected item information to fragment
Bundle data = new Bundle();
data.putInt("position", position);
data.putString("url", getUrl(position));
rFragment.setArguments(data);

// Getting reference to the FragmentManager
FragmentManager fragmentManager = getFragmentManager();

// Creating a fragment transaction
FragmentTransaction ft = fragmentManager.beginTransaction();

// Adding a fragment to the fragment transaction
ft.replace(R.id.content_frame, rFragment);

// Committing the transaction
ft.commit();


2) The ability to change text when the drawer is opened and closed

mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_drawer, R.string.drawer_open,
R.string.drawer_close) {

/** Called when drawer is closed */
public void onDrawerClosed(View view) {
getActionBar().setTitle(mTitle);
invalidateOptionsMenu();
}

/** Called when a drawer is opened */
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle("JAVATECHIG.COM");
invalidateOptionsMenu();
}

};


Friday, September 2, 2011

Implementing USB HID Interface in Android 3.1

If there is a chance that the application will close, then you must close and release the device. If you don't to this, then the user probably won't be able to open the device again until it is re-plugged. In order to prevent this issue, then you might need to consider creating the device interface as a service.



Documentation for using USB Host can be found at http://developer.android.com/guide/topics/usb/host.html. The following are some of the feature that I had to implement in order to get the interface working. 





AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      ... >
      <uses-sdk android:minSdkVersion="12" />
      <uses-feature android:name="android.hardware.usb.host" />



HIDInterface.java



BroadcastReceiver - This is required to receive the registered events
/*
 * Receives a requested broadcast from the operating system.
 * In this case the following actions are handled:
 * USB_PERMISSION
 * UsbManager.ACTION_USB_DEVICE_DETACHED
 * UsbManager.ACTION_USB_DEVICE_ATTACHED
 */
private final BroadcastReceiver usbReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
// Validate the action against the actions registered
...
}
};

Requesting Permission - In order to connect to the device, the user has to give their permission. This must be implemented in the BroadcastReceiver that will handle the response to the question when it is displayed to the user.

The variable 
private static final String ACTION_USB_PERMISSION = "com.access.device.USB_PERMISSION"; 
is a predefined variable for registering to receive device permissions.

The BroadcastReceiver code
if (ACTION_USB_PERMISSION.equals(action))
{
// A permission response has been received, validate if the user has 
// GRANTED, or DENIED permission
synchronized (this)
{
UsbDevice deviceConnected = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false))
{
// Permission has been granted, so connect to the device
// If this fails, then keep looking
if (deviceConnected != null)
{
// call method to setup device communication
currentDevice = deviceConnected;
if (ShowDebuggingToasts)
{
Toast.makeText(hostDisplayActivity, "Device Permission Acquired", Toast.LENGTH_SHORT).show();
}
if (!ConnectToDeviceInterface(currentDevice))
{
if (ShowDebuggingToasts)
{
Toast.makeText(hostDisplayActivity, "Unable to connect to device", Toast.LENGTH_SHORT).show();
}
}
sendEnabledMessage();
// Create a listener to receive messages from the host
...
}
}
else
{
// Permission has not been granted, so keep looking for another
// device to be attached....
if (ShowDebuggingToasts)
{
Toast.makeText(hostDisplayActivity, "Device Permission Denied", Toast.LENGTH_SHORT).show();
}
currentDevice = null;
}
}
}
}

Registering the intent
usbManager = (UsbManager) hostDisplayActivity.getSystemService(Context.USB_SERVICE);
permissionIntent = PendingIntent.getBroadcast(hostDisplayActivity, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter permissionFilter = new IntentFilter(ACTION_USB_PERMISSION);
hostDisplayActivity.registerReceiver(usbReceiver, permissionFilter);


Requesting permission
UsbDevice currentDevice = .....;
usbManager.requestPermission(currentDevice, permissionIntent);



Device Attached and Detached Intents - Handling a device attached or detached intent, requires that the user register them first.

Registering the intent
usbManager = (UsbManager) hostDisplayActivity.getSystemService(Context.USB_SERVICE);
IntentFilter deviceAttachedFilter = new IntentFilter();
deviceAttachedFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
deviceAttachedFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
hostDisplayActivity.registerReceiver(usbReceiver, deviceAttachedFilter);

The BroadcastReceiver code

if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action))
{
// A device has been detached from the device, so close all the connections
// and restart the search for a new device being attached
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if ((device != null) && (currentDevice != null))
{
if (device.equals(currentDevice))
{
// call your method that cleans up and closes communication with the device
CleanUpAndClose();
}
}
}
else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action))
{
// A device has been attached. If not already connected to a device,
// validate if this device is supported
UsbDevice searchDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if ((searchDevice != null) && (currentDevice == null))
{
// call your method that cleans up and closes communication with the device
ValidateFoundDevice(searchDevice);
}
}




Validating the Connected Device - Before asking for permission to connect to the device, it is essential that you ensure that this is a device that you support or expect to connect to. This can be done by validating the devices Vendor ID and Product ID.

A vendor id is a global identifier for the manufacturer. A product id refers to the product itself, and is unique to the manufacturer. The vendor id, product id combination refers to a particular product manufactured by a vendor.

searchDevice.getProductId()
searchDevice.getVendorId()



Connecting to the Device - If you are reading and writing, then the device can either have two end points on a single interface, or two interfaces each with a single end point. Either way, it is best if you know which interface you need to use and which end points.


UsbInterface usbInterfaceRead = null;
UsbInterface usbInterfaceWrite = null;
UsbEndpoint ep1 = null;
UsbEndpoint ep2 = null;
boolean UsingSingleInterface = false;


if (UsingSingleInterface)
{
// Using the same interface for reading and writing
usbInterfaceRead = connectDevice.getInterface(0x00);
usbInterfaceWrite = usbInterfaceRead;
if (usbInterfaceRead.getEndpointCount() == 2)
{
ep1 = usbInterfaceRead.getEndpoint(0);
ep2 = usbInterfaceRead.getEndpoint(1);
}
}
else        // if (!UsingSingleInterface)
{
usbInterfaceRead = connectDevice.getInterface(0x00);
usbInterfaceWrite = connectDevice.getInterface(0x01);
if ((usbInterfaceRead.getEndpointCount() == 1) && (usbInterfaceWrite.getEndpointCount() == 1))
{
ep1 = usbInterfaceRead.getEndpoint(0);
ep2 = usbInterfaceWrite.getEndpoint(0);
}
}


if ((ep1 == null) || (ep2 == null))
{
return false;
}

// Determine which endpoint is the read, and which is the write

if (ep1.getType() == UsbConstants.USB_ENDPOINT_XFER_INT)
{
if (ep1.getDirection() == UsbConstants.USB_DIR_IN)
{
usbEndpointRead = ep1;
}
else if (ep1.getDirection() == UsbConstants.USB_DIR_OUT)
{
usbEndpointWrite = ep1;
}
}
if (ep2.getType() == UsbConstants.USB_ENDPOINT_XFER_INT)
{
if (ep2.getDirection() == UsbConstants.USB_DIR_IN)
{
usbEndpointRead = ep2;
}
else if (ep2.getDirection() == UsbConstants.USB_DIR_OUT)
{
usbEndpointWrite = ep2;
}
}
if ((usbEndpointRead == null) || (usbEndpointWrite == null))
{
return false;
}
connectionRead = usbManager.openDevice(connectDevice);
connectionRead.claimInterface(usbInterfaceRead, true);


if (UsingSingleInterface)
{
connectionWrite = connectionRead;
}
else // if (!UsingSingleInterface)
{
connectionWrite = usbManager.openDevice(connectDevice);
connectionWrite.claimInterface(usbInterfaceWrite, true);
}

// Start the read thread



Writing to the Device - Some devices require the controlTransfer method for writing data. I don't cover this command in this blog. As USB devices work with reports of a specific length. It is best to format the data being sent into a ByteBuffer of the correct length. The length required can be retrieved from the endpoint.

int bufferDataLength = usbEndpointWrite.getMaxPacketSize();

The report must be formatted correctly for the device being connected to. On some devices, this requires that a specific value must be the first byte in the report. This can be followed by the length of the data in the report. This format is determined by the device, and isn't specified here.

int bufferDataLength = usbEndpointWrite.getMaxPacketSize();
ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength + 1);
UsbRequest request = new UsbRequest();

buffer.put(DataToSend);

request.initialize(connectionWrite, usbEndpointWrite);
request.queue(buffer, bufferDataLength);
try
{
if (request.equals(connectionWrite.requestWait()))
{
return true;
}
}
catch (Exception ex)
{
// An exception has occured
}



Reading from the Device - As USB devices work with reports of a specific length. The data received from the device will always be the size specified by the report length. Even if there isn't enough data to fill the report. Some devices require the controlTransfer method for reading data. I don't cover this command in this blog.

If you are expecting unsolicited data from the device, then a read thread should be started so that the data can be processed as soon as it arrives. 

int bufferDataLength = usbEndpointRead.getMaxPacketSize();
ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength + 1);
UsbRequest requestQueued = null;
UsbRequest request = new UsbRequest();
request.initialize(connectionRead, usbEndpointRead);

try
{
while (!getStopping())
{
request.queue(buffer, bufferDataLength);
requestQueued = connectionRead.requestWait();
if (request.equals(requestQueued))
{
byte[] byteBuffer = new byte[bufferDataLength + 1];
buffer.get(byteBuffer, 0, bufferDataLength);

// Handle data received
... 

buffer.clear();
}
else
{
Thread.sleep(20);
}
}
}
catch (Exception ex)
{
// An exception has occured
}
try
{
request.cancel();
request.close();
}
catch (Exception ex)
{
// An exception has occured
}




This isn't the most comprehensive or complete document, but hopefully it will help someone to implement a USB Host Device interface.






Monday, August 22, 2011

Getting A500 ACER Iconia Tablet Driver Working With Android 3.1

I downloaded the latest version and installed it, but could not get ADB to work. In order to get the ADB working, I had to edit the android_usb.inf file located in C:\Program Files\Acer Inc\ACER ICONIA TAB\Win7\ADB\x86 by adding the following lines.

[ACER.NTx86]

%USB\VID_0502&PID_3325.DeviceDescRelease%=androidusb.Dev, USB\VID_0502&PID_3325

%ACERFASTBOOT%=androidusb.Dev, USB\VID_0502&PID_3325

[Strings]
USB\VID_0502&PID_3325.DeviceDescRelease="ACER Composite ADB Interface"
USB\VID_0502&PID_3202&MI_01.DeviceDescRelease="ACER Composite ADB Interface"

Sunday, January 9, 2011

Adding NTLM authentication

I had some trouble adding NTLM authentication as it doesn't seem to be there by default. I need the authentication as I have to be able to access a Microsoft IIS Web Server using standard windows user authentication.

In order to do this I
- used an example from :
     http://hc.apache.org/httpcomponents-client-ga/ntlm.html

- downloaded the latest JCIFS library from :
     http://jcifs.samba.org

- Changed the Type3Message initialisation in the JCIFSEngine class as it isn't
   supported by he version of JCIFS that I downloaded

        Type3Message t3m = new Type3Message(
                t2m,
                password,
                domain,
                username,
                workstation);

     was changed to

        Type3Message t3m = new Type3Message(
                t2m); //,
//                password,
//                domain,
//                username,
//                workstation);
        t3m.setNTResponse(Type3Message.getNTResponse(t2m, password));
        t3m.setLMResponse(Type3Message.getLMResponse(t2m, password));
        t3m.setDomain(domain);
        t3m.setUser(username);
        t3m.setWorkstation(workstation);

I don't know if that is the correct way to do it, but it works.

Thursday, December 30, 2010

Eclipse Errors

All the errors are cleared, but they are still in the Problems list and the project won't build.

Select the error in the problems list and click the delete button.
Clean the project by using the menu option Project >  Clean.
Rebuild and try again.

AndroidManifest XML file

Adding Activity to Android Project


I followed the Tab Layout Tutorial on Android Developers (http://developer.android.com/resources/tutorials/views/hello-tabwidget.html), but couldn't get the tabs to work.


When you add activity classes to the project, you must and the activity to the android manifest (AndroidManifest.xml) file.


Example:
public class SecondTab extends Activity {
...
}


must have the following line in the AndroidManifest.xml file
<activity android:name=".SecondTab" />



Adding uses-permission


Must be in the manifest portion of the xml file


Example:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.???.???"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
    ...
    </application>
    <uses-permission android:name="android.permission.INTERNET" />
</manifest>