List attached USB devices in USB Host mode

In this exercise, my Android phone (HTC One X) act as USB Host to list attached USB devices via USB OTG cable. It target devices with minSdkVersion="12".

Listed result without any extra device attached.

With card reader attached, via USB OTG cable.

With another Nexus One attached as slave, via USB OTG cable.


To specify the app to be run as UDB Host, add uses-feature of "android.hardware.usb.host", and android:minSdkVersion="12" in AndroidManifest.xml.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidusbhost"
android:versionCode="1"
android:versionName="1.0" >

<uses-feature android:name="android.hardware.usb.host" />
<uses-sdk
android:minSdkVersion="12"
android:targetSdkVersion="18" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.androidusbhost.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>


Main Java code.
package com.example.androidusbhost;

import java.util.HashMap;
import java.util.Iterator;

import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.app.Activity;
import android.content.Context;

public class MainActivity extends Activity {

Button btnCheck;
TextView textInfo;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnCheck = (Button) findViewById(R.id.check);
textInfo = (TextView) findViewById(R.id.info);
btnCheck.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {
checkInfo();
}
});
}

private void checkInfo() {
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();

String i = "";
while (deviceIterator.hasNext()) {
UsbDevice device = deviceIterator.next();
i += "\n" +
"DeviceID: " + device.getDeviceId() + "\n" +
"DeviceName: " + device.getDeviceName() + "\n" +
"DeviceClass: " + device.getDeviceClass() + " - "
+ translateDeviceClass(device.getDeviceClass()) + "\n" +
"DeviceSubClass: " + device.getDeviceSubclass() + "\n" +
"VendorID: " + device.getVendorId() + "\n" +
"ProductID: " + device.getProductId() + "\n";
}

textInfo.setText(i);
}

private String translateDeviceClass(int deviceClass){
switch(deviceClass){
case UsbConstants.USB_CLASS_APP_SPEC:
return "Application specific USB class";
case UsbConstants.USB_CLASS_AUDIO:
return "USB class for audio devices";
case UsbConstants.USB_CLASS_CDC_DATA:
return "USB class for CDC devices (communications device class)";
case UsbConstants.USB_CLASS_COMM:
return "USB class for communication devices";
case UsbConstants.USB_CLASS_CONTENT_SEC:
return "USB class for content security devices";
case UsbConstants.USB_CLASS_CSCID:
return "USB class for content smart card devices";
case UsbConstants.USB_CLASS_HID:
return "USB class for human interface devices (for example, mice and keyboards)";
case UsbConstants.USB_CLASS_HUB:
return "USB class for USB hubs";
case UsbConstants.USB_CLASS_MASS_STORAGE:
return "USB class for mass storage devices";
case UsbConstants.USB_CLASS_MISC:
return "USB class for wireless miscellaneous devices";
case UsbConstants.USB_CLASS_PER_INTERFACE:
return "USB class indicating that the class is determined on a per-interface basis";
case UsbConstants.USB_CLASS_PHYSICA:
return "USB class for physical devices";
case UsbConstants.USB_CLASS_PRINTER:
return "USB class for printers";
case UsbConstants.USB_CLASS_STILL_IMAGE:
return "USB class for still image devices (digital cameras)";
case UsbConstants.USB_CLASS_VENDOR_SPEC:
return "Vendor specific USB class";
case UsbConstants.USB_CLASS_VIDEO:
return "USB class for video devices";
case UsbConstants.USB_CLASS_WIRELESS_CONTROLLER:
return "USB class for wireless controller devices";
default: return "Unknown USB class!";

}
}
}


layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />
<Button
android:id="@+id/check"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Check USB devices" />
<TextView
android:id="@+id/info"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</LinearLayout>


download filesDownload the files.

Next: - List UsbDevice, UsbInterface and UsbEndpoint in USB Host mode



Step-by-step: Android USB Host Mode programming

Learn OpenGL ES: For Mobile Game and Graphics Development

Release date: August 30, 2013 | ISBN-10: 1430250534 | ISBN-13: 978-1430250531 | Edition: 1

Want to create sophisticated games and graphics-intensive apps? Learn OpenGL ES gets you started immediately with OpenGL ES.  After mastering the basics of OpenGL ES itself, you will quickly find yourself writing and building game apps, without having to learn about object oriented programming techniques.

This book demonstrates the use of a powerful open-source modeling tool, Blender. You will be guided, step by step, through the development of Tank Fence, a dynamic, interactive 3D game. Along the way you'll gain skills in building apps with Eclipse and the Android SDK or NDK, rendering graphics using hardware acceleration, and multithreading for performance and responsiveness. iOS developers will also find this book's information invaluable when writing their apps.

You'll learn everything you need to know about:
  • Creating simple, efficient game UIs
  • Designing the basic building blocks of an exciting, interactive 3D game
  • Pulling all the elements together with Blender, a powerful open-source tool for modeling, animation, rendering, compositing, video editing, and game creation
  • Taking the next big step using custom and inbuilt functions, texturing, shading, light sources, and more
  • Refining your mobile game app through collision detection, player-room-obstacle classes, and storage classes
  • Doing all this efficiently on mobile devices with limited resources and processing
What you’ll learn
  • How to install and use OpenGL ES 2.0 on Android
  • GLSL ES Fundamentals
  • State Management
  • Modeling 3D Objects Using Blender
  • Using the Perl Mesh Parser
  • Vertex Buffer Objects
  • Using Color Masks
  • sampler2D and samplerCube Uniforms
  • Multi-Texturing
  • Lambert Illumination Model
  • Implementing the Lighting Equation
  • Design, write, and build Tank Fence, an interactive 3D game
Who this book is for

Learn OpenGL ES is ideal for mobile game and interactive app developers who want to know more about the OpenGL ES engine and and use it to build more sophisticated, graphically-rich games and other apps. While the code is developed on Android, iOS developers will also find this book invaluable.

Table of Contents
1. Why OpenGL ES?
2. UI for games: Keep it simple
3. First Steps:  Mobile Game App Development
4. 3D Modeling
5. Functions, Shading, Light Source and Objects
6. Carrying Further: Collision Detection

Some example of simple styled button

Some example of simple styled button


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />

<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Default Button" />

<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/ic_launcher"
android:text="Button with background of drawable, no CLICK visual effect" />

<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#550000ff"
android:text="Button with background of color, no CLICK visual effect" />

<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:drawableRight="@drawable/ic_launcher"
android:text="Button with drawableRight" />

<ImageButton
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />

<Button
style="?android:attr/borderlessButtonStyle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Button with borderlessButtonStyle (for API 11+)" />

<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:shadowColor="#000000"
android:shadowDx="5"
android:shadowDy="5"
android:shadowRadius="10"
android:text="Button with shadow on Text" />

<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:shadowColor="#000000"
android:text="Button with Styled Text"
android:textStyle="bold|italic" />

</LinearLayout>


Connecting your Android App to Azure Mobile Services (including Android Dev Tools setup)



Chris Risner and Nick Harris have  a set of excellent Mobile Services videos in the Windows Azure area of Channel 9 here.

The video in this post is for those of you who have no experience with the Android Development Tools (ADT). You'll get some errors with the latest build of the ADT unless you follow the ADT setup instructions in this video.

I'd suggest following along with this video to set up the ADT and then watching Chris and Nick's excellent set of Mobile Services videos to extend your knowledge.

Source: http://channel9.msdn.com/posts/Connecting-your-Android-App-to-Azure-Mobile-Services-including-Android-Dev-Tools-setup

Blur bitmap

This exercise generate a blur bitmap by changing each pixel to the average of its surrounding 5x5 pixel.

Blur bitmap


package com.example.androiddrawbitmap;

import java.io.FileNotFoundException;

import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class MainActivity extends Activity {

Button btnLoadImage;
ImageView imageResult, imageOriginal;
TextView textDur;

final int RQS_IMAGE1 = 1;

Uri source;
Bitmap bitmapMaster;
Canvas canvasMaster;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

btnLoadImage = (Button) findViewById(R.id.loadimage);
imageResult = (ImageView) findViewById(R.id.result);
imageOriginal = (ImageView)findViewById(R.id.original);
textDur = (TextView)findViewById(R.id.dur);

btnLoadImage.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {
Intent intent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_IMAGE1);
}
});
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (resultCode == RESULT_OK) {
switch (requestCode) {
case RQS_IMAGE1:
source = data.getData();

try {
bitmapMaster = BitmapFactory
.decodeStream(getContentResolver().openInputStream(
source));

imageOriginal.setImageBitmap(bitmapMaster);
loadBlurBitmap(bitmapMaster);

} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

break;
}
}
}

private void loadBlurBitmap(Bitmap src) {
if (src != null) {

Bitmap bmBlur;

long startTime = System.currentTimeMillis();
bmBlur = getBlurBitmap(src);
long duration = System.currentTimeMillis() - startTime;

imageResult.setImageBitmap(bmBlur);
textDur.setText("processing duration(ms): " + duration);
}
}

private Bitmap getBlurBitmap(Bitmap src) {

final int widthKernal = 5;
final int heightKernal = 5;

int w = src.getWidth();
int h = src.getHeight();

Bitmap blurBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);

for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {

int r = 0;
int g = 0;
int b = 0;
int a = 0;

for (int xk = 0; xk < widthKernal; xk++) {
for (int yk = 0; yk < heightKernal; yk++) {
int px = x + xk -2;
int py = y + yk -2;

if(px < 0){
px = 0;
}else if(px >= w){
px = w-1;
}

if(py < 0){
py = 0;
}else if(py >= h){
py = h-1;
}

int intColor = src.getPixel(px, py);
r += Color.red(intColor);
g += Color.green(intColor);
b += Color.blue(intColor);
a += Color.alpha(intColor);

}
}

blurBitmap.setPixel(x, y, Color.argb(a/25, r/25, g/25, b/25));

}
}

return blurBitmap;
}

}


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/background_dark"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />

<Button
android:id="@+id/loadimage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Load Image 1" />

<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="@+id/original"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitXY" />
<ImageView
android:id="@+id/result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitXY" />
<TextView
android:id="@+id/dur"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</ScrollView>
</LinearLayout>

download filesDownload the files.

download filesDownload and try the APK.



more: Something about processing images in Android

Android Studio Canary Build 0.2.13 released

Android Studio Canary Build 0.2.13 released. Visit: http://tools.android.com/download/studio/canary/latest

It's the first release in the Canary Channel for Android Studio, which delivers updates on a roughly weekly basis.

GridView example: load images to GridView from SD Card in background

Recall from the "old exercise of GridView", loading images to GridView from SD Card in onCreate() method running in main thread. Actually, it may take long time to finish, so it should be moved to background thread. This exercise move the file loading operation to AsyncTask running in background thread.

Also introduce Reload button to demonstrate how to clear and reload the list.

Load images to GridView from SD Card


Here are some notes in my implementation:
  • In my trial experience, should not access ImageAdapter(extends BaseAdapter) from background thread such as doInBackground(). Doing so will conflict with ImageAdapter's getView() method, and generate IndexOutOfBoundsException occasionally. It whould be accessed in UI thread, so the clear(), add() and notifyDataSetChanged() have been moved to onPreExecute(), onProgressUpdate() and onPostExecute().
  • Cancel the AsyncTask if not need.
  • In my approach, always new another ImageAdapter when reloading; to prevent the list inside mixed with a invalid but still running AsyncTask.

package com.example.androidgridview;

import java.io.File;
import java.util.ArrayList;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends Activity {

AsyncTaskLoadFiles myAsyncTaskLoadFiles;

public class AsyncTaskLoadFiles extends AsyncTask<Void, String, Void> {

File targetDirector;
ImageAdapter myTaskAdapter;

public AsyncTaskLoadFiles(ImageAdapter adapter) {
myTaskAdapter = adapter;
}

@Override
protected void onPreExecute() {
String ExternalStorageDirectoryPath = Environment
.getExternalStorageDirectory().getAbsolutePath();

String targetPath = ExternalStorageDirectoryPath + "/test/";
targetDirector = new File(targetPath);
myTaskAdapter.clear();

super.onPreExecute();
}

@Override
protected Void doInBackground(Void... params) {

File[] files = targetDirector.listFiles();
for (File file : files) {
publishProgress(file.getAbsolutePath());
if (isCancelled()) break;
}
return null;
}

@Override
protected void onProgressUpdate(String... values) {
myTaskAdapter.add(values[0]);
super.onProgressUpdate(values);
}

@Override
protected void onPostExecute(Void result) {
myTaskAdapter.notifyDataSetChanged();
super.onPostExecute(result);
}

}

public class ImageAdapter extends BaseAdapter {

private Context mContext;
ArrayList<String> itemList = new ArrayList<String>();

public ImageAdapter(Context c) {
mContext = c;
}

void add(String path) {
itemList.add(path);
}

void clear() {
itemList.clear();
}

void remove(int index){
itemList.remove(index);
}

@Override
public int getCount() {
return itemList.size();
}

@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return itemList.get(position);
}

@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) { // if it's not recycled, initialize some
// attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(220, 220));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
}

Bitmap bm = decodeSampledBitmapFromUri(itemList.get(position), 220,
220);

imageView.setImageBitmap(bm);
return imageView;
}

public Bitmap decodeSampledBitmapFromUri(String path, int reqWidth,
int reqHeight) {

Bitmap bm = null;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);

// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);

// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeFile(path, options);

return bm;
}

public int calculateInSampleSize(

BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;

if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float) height
/ (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}

return inSampleSize;
}

}

ImageAdapter myImageAdapter;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

final GridView gridview = (GridView) findViewById(R.id.gridview);
myImageAdapter = new ImageAdapter(this);
gridview.setAdapter(myImageAdapter);

/*
* Move to asyncTaskLoadFiles String ExternalStorageDirectoryPath =
* Environment .getExternalStorageDirectory() .getAbsolutePath();
*
* String targetPath = ExternalStorageDirectoryPath + "/test/";
*
* Toast.makeText(getApplicationContext(), targetPath,
* Toast.LENGTH_LONG).show(); File targetDirector = new
* File(targetPath);
*
* File[] files = targetDirector.listFiles(); for (File file : files){
* myImageAdapter.add(file.getAbsolutePath()); }
*/
myAsyncTaskLoadFiles = new AsyncTaskLoadFiles(myImageAdapter);
myAsyncTaskLoadFiles.execute();

gridview.setOnItemClickListener(myOnItemClickListener);

Button buttonReload = (Button)findViewById(R.id.reload);
buttonReload.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View arg0) {

//Cancel the previous running task, if exist.
myAsyncTaskLoadFiles.cancel(true);

//new another ImageAdapter, to prevent the adapter have
//mixed files
myImageAdapter = new ImageAdapter(MainActivity.this);
gridview.setAdapter(myImageAdapter);
myAsyncTaskLoadFiles = new AsyncTaskLoadFiles(myImageAdapter);
myAsyncTaskLoadFiles.execute();
}});

}

OnItemClickListener myOnItemClickListener = new OnItemClickListener() {

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
String prompt = "remove " + (String) parent.getItemAtPosition(position);
Toast.makeText(getApplicationContext(), prompt, Toast.LENGTH_SHORT)
.show();

myImageAdapter.remove(position);
myImageAdapter.notifyDataSetChanged();

}
};

}


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<Button
android:id="@+id/reload"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Reload"/>
<GridView
android:id="@+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="90dp"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"/>

</LinearLayout>


download filesDownload the files.

download filesDownload and try the APK.



Next:
- getView() to load images in AsyncTask