What's New in Android 4.4

DevBytes: What's New in Android 4.4

KitKat has been optimized to run on a much broader range of devices, with special focus on the millions of entry-level devices that have as little as 512MB RAM. To help, new APIs have been created, better tools, and better documentation to let you create apps that perform well on all devices.

Check out this video summary of some of the most significant developer features in the latest Android release, including new ways to make your apps beautiful, NFC Host Card Emulation, a printing framework, the storage access framework, low-power step detector and step counter sensors, and more!

Be sure to get the full Android 4.4 API Overview
http://developer.android.com/about/versions/android-4.4.html

And take a look at related DevBytes videos:
https://www.youtube.com/playlist?list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K

Google Play Services 4.0

Google are launching Google Play services 4.0, includes the Google Mobile Ads SDK, and offers improvements to geofencing, Google+, and Google Wallet Instant Buy APIs. And dropping support for Froyo from this release of the Google Play services SDK.

source: Android Developers Blog

Android 4.4 (KitKat) includes a new WebView component based on the Chromium

Android 4.4 (KitKat) includes a new WebView component based on the Chromium open source project. The new WebView includes an updated version of the V8 JavaScript engine and support for modern web standards that were missing in the old WebView. It also shares the same rendering engine as Chrome for Android, so rendering should be much more consistent between the WebView and Chrome.

If you're a web developer looking to start developing a WebView-based Android application, see Getting Started: WebView-based Applications for Web Developers.

Source: https://developers.google.com/chrome/mobile/docs/webview/overview

The new Nexus 5, Now available in two memory versions and two colors

The new Nexus 5, now available in two memory versions and two colors, 16GB for $349 and 32GB for $399.



Visit: http://www.google.com/nexus/5/

Google Nexus 5: I Do

Enterprise Android: Programming Android Database Applications for the Enterprise

The definitive guide to building data-driven Android applications for enterprise systems


Android devices represent a rapidly growing share of the mobile device market. With the release of Android 4, they are moving beyond consumer applications into corporate/enterprise use. Developers who want to start building data-driven Android applications that integrate with enterprise systems will learn how with this book. In the tradition of Wrox Professional guides, it thoroughly covers sharing and displaying data, transmitting data to enterprise applications, and much more.
  • Shows Android developers who are not familiar with database development how to design and build data-driven applications for Android devices and integrate them with existing enterprise systems
  • Explores how to collect and store data using SQLite, share data using content providers, and display data using adapters
  • Covers migrating data using various methods and tools; transmitting data to the enterprise using web services; serializing, securing, and synchronizing data
  • Shows how to take advantage of the built-in capabilities of the Android OS to integrate applications into enterprise class systems
Enterprise Android prepares any Android developer to start creating data-intensive applications that today’s businesses demand

October 28, 2013  1118183495  978-1118183496 1


Basic setup for Microsoft Remote Desktop and Remote Desktop Client for Android


Setup in the video:
- Windows 8.1 Pro running on a slow and outdate Netbook, BenQ Joybook Lite U101 with Aton N270, connect router with cable.
- HTC One X running Android 4.2.2, connect via WiFi.
- HTC Fly running Android 3.2.1, connect via WiFi.


Before establish connection between host PC and remote client app, you have to setup in both PC side and client side.

Set up your Remote Desktop in host PC. (This example running Windows 8.1 Pro)

- Enter "Remote Desktop" in Search, select "Select users who can use remote desktop".


- Under Remote tab, enable "Allow remote connections to this computer" under Remote Desktop. Click the "Select Users" button.


remark: what type of connection should be allowed?

Network Level Authentication (NLA) is an authentication method that completes user authentication before you establish a full connection and the sign-in screen appears. This can help protect the remote PC from hackers and malware.
  • To prevent anyone from connecting to your PC using Remote Desktop or RemoteApp and Desktop Connections, pick Don’t allow remote connections to this computer.
  • If you don't know which version of Remote Desktop Connection other people are using, pick Allow remote connections to this computer.
  • If you know that the people who will connect to your PC are running Windows 7 or Windows 8 on their PCs, check the Only allow connections from computers running Remote Desktop with Network Level Authentication (recommended) box.
Reference: What types of Remote Desktop connections should I allow?

- Click "Add" button.


- Select "Users" in Select the object type. Enter object name and click "Check Names", to get the selected object.


- OK.


- and OK.


 Install and start "Microsoft Remote Desktop" for Android.

Set up your Remote Desktop Client in Android side.

- Select "Remote Desktops" and click the "+".


- Enter Connection, IP address in PC name, User name and Password. And click the check mark on upper-right.


Read the Official FAQ.





update@2013-10-31

Somebody said cannot see "Select users who can use remote desktop" when search "Remote Desktop".

This video show how to, remember the tag after Search is select Everywhere or Settings. If you select Files, Web images or Web videos, "Select users who can use remote desktop" will not appear.





update@2013-12-31
Fix problem of "Remote Desktop blocked by Windows Firewall."

Project Shield - Using Google's infrastructure to protect freedom of expression

Project Shield is an initiative to use Google's infrastructure to protect free expression online. The service currently combines Google's DDoS mitigation technologies and Page Speed Service (PSS), which allow websites to serve their content through Google to be better protected from DDoS attacks. The service is currently seeking 'trusted testers' and people with sites that serve media, elections and human rights-related content are invited to apply for an invite at g.co/projectshield

Getting Started with Remote Desktop Client on mobile

Microsoft release Remote Desktop Client for Android and iOS recently. Users can use the Microsoft Remote Desktop Client to connect to a remote PC and your work resources from almost anywhere.

Download here:
- for Android from Google Play
- for iOS from iTune




***To establish connection between Microsoft Remote Desktop Client to connect between remote PC, you have to do some setup. Refer to the document: Microsoft Remote Desktop Clients.



In my RD Client on Android, the setup of Remote Desktops is something like it:

Updated: Basic setup for Microsoft Remote Desktop and Remote Desktop Client for Android


Sharpen bitmap using Convolution

The previous exercise "Blur bitmap using Convolution". By changing the matrix of Convolution class, we can use it to sharpen bitmap.

 class Convolution {

// matrix to sharpen image
int[][] matrix = { { 0, -1, 0 }, { -1, 5, -1 }, { 0, -1, 0 } };
...


Sharpen bitmap using Convolution




more: Something about processing images in Android

Windows 8 customers can update to Windows 8.1 starting from October 17th, 2013

Beginning October 17th, 2013, Windows 8 customers can update to Windows 8.1 for free in the Windows Store! With the return of the Start button, new ways to personalize your Start screen, and more ways to do more things at once, the new Windows gives you one experience for everything in your life.

Windows 8.1 Everywhere


http://msft.it/NewWindows

Blur bitmap using Convolution

The previous exercise blur bitmap by averaging pixels with surrounding pixels. In this exercise, we are going to implement a class of Convolution, to blur bitmap with Convolution Matrix.

Blur bitmap using Convolution


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) {
e.printStackTrace();
}

break;
}
}
}

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

Bitmap bmBlur;
Convolution convolution = new Convolution();

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

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

class Convolution {

// matrix to blur image
int[][] matrix = { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } };
// kernal_width x kernal_height = dimension pf matrix
// halfWidth = (kernal_width - 1)/2
// halfHeight = (kernal_height - 1)/2
int kernal_width = 3;
int kernal_height = 3;
int kernal_halfWidth = 1;
int kernal_halfHeight = 1;

public Bitmap convBitmap(Bitmap src) {

int[][] sourceMatrix = new int[kernal_width][kernal_height];

// averageWeight = total of matrix[][]. The result of each
// pixel will be divided by averageWeight to get the average
int averageWeight = 0;
for (int i = 0; i < kernal_width; i++) {
for (int j = 0; j < kernal_height; j++) {
averageWeight += matrix[i][j];
}
}
if (averageWeight == 0) {
averageWeight = 1;
}

int pixelR, pixelG, pixelB, pixelA;

int w = src.getWidth();
int h = src.getHeight();
Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);

// fill sourceMatrix with surrounding pixel
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {

for (int xk = 0; xk < kernal_width; xk++) {
for (int yk = 0; yk < kernal_height; yk++) {
int px = x + xk - kernal_halfWidth;
int py = y + yk - kernal_halfHeight;

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

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

sourceMatrix[xk][yk] = src.getPixel(px, py);

}
}

pixelR = pixelG = pixelB = pixelA = 0;

for (int k = 0; k < kernal_width; k++) {
for (int l = 0; l < kernal_height; l++) {

pixelR += Color.red(sourceMatrix[k][l])
* matrix[k][l];
pixelG += Color.green(sourceMatrix[k][l])
* matrix[k][l];
pixelB += Color.blue(sourceMatrix[k][l])
* matrix[k][l];
pixelA += Color.alpha(sourceMatrix[k][l])
* matrix[k][l];
}
}
pixelR = pixelR / averageWeight;
pixelG = pixelG / averageWeight;
pixelB = pixelB / averageWeight;
pixelA = pixelA / averageWeight;

if (pixelR < 0) {
pixelR = 0;
} else if (pixelR > 255) {
pixelR = 255;
}

if (pixelG < 0) {
pixelG = 0;
} else if (pixelG > 255) {
pixelG = 255;
}

if (pixelB < 0) {
pixelB = 0;
} else if (pixelB > 255) {
pixelB = 255;
}

if (pixelA < 0) {
pixelA = 0;
} else if (pixelA > 255) {
pixelA = 255;
}

bm.setPixel(x, y,
Color.argb(pixelA, pixelR, pixelG, pixelB));
}
}

return bm;
}
}
}


Keep using layout in the post Blur bitmap.

download filesDownload the files.

download filesDownload and try the APK.

Next: By changing the matrix in Convolution class, we can use it to sharpen bitmap.


more: Something about processing images in Android

USB On the Go, for HTC



If your Android support USB OTG, you can access USB Storage via USB OTG cable. (Please notice that not all devices support this feature)

Here is a post describe using of USB On the Go for HTC device from HTC Blog: http://blog.htc.com/usb-otg/

  • First, get your USB OTG cable ready
  • Plug your USB drive into the USB port on the cable, then plug the cable into your phones microUSB port.
  • Now you can access the data on your USB drive through your HTC smartphone. Using USB OTG, you can use apps like Gallery, Music and Polaris Office to easily access files on your USB drive and your smartphone.
  • When you’re done, you can quickly check available storage on your USB drive by going to Setting > Storage on your HTC phone.  Also, don’t forget to unmount your USB drive when you’re finished.

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


Example to apply BlurMaskFilter on Bitmap

apply BlurMaskFilter on 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.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity {

Button btnLoadImage;
ImageView imageResult;

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);

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));
loadGrayBitmap(bitmapMaster);

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

break;
}
}
}

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

int w = src.getWidth();
int h = src.getHeight();
RectF rectF = new RectF(w/4, h/4, w*3/4, h*3/4);
float blurRadius = 100.0f;

Bitmap bitmapResult = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvasResult = new Canvas(bitmapResult);

Paint blurPaintOuter = new Paint();
blurPaintOuter.setColor(0xFFffffff);
blurPaintOuter.setMaskFilter(new
BlurMaskFilter(blurRadius, BlurMaskFilter.Blur.INNER));
canvasResult.drawBitmap(bitmapMaster, 0, 0, blurPaintOuter);

Paint blurPaintInner = new Paint();
blurPaintInner.setColor(0xFFffffff);
blurPaintInner.setMaskFilter(new
BlurMaskFilter(blurRadius, BlurMaskFilter.Blur.OUTER));
canvasResult.drawRect(rectF, blurPaintInner);

imageResult.setImageBitmap(bitmapResult);
}
}
}


<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"
android:background="@android:color/background_dark"
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" />

<ImageView
android:id="@+id/result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="centerInside" />

</LinearLayout>


download filesDownload the files.



more: Something about processing images in Android

Learn how to use the Android NDK, by creating an image processing application

The Android Software Developer Kit (SDK) used by the majority of Android application developers requires the use of the Java™ programming language. However, there is a large body of C language code available online. The Android Native Developer Kit (NDK) permits an Android developer to reuse existing C source code within an Android application. The tutorial, Reuse existing C code with the Android NDK by IBM 12 Apr 2011, introduce how to create an image processing application in the Java programming language that uses C code to perform basic image processing operations.

The tutorial is available in PDF format (773 KB | 42 pages) also.

Reuse existing C code with the Android NDK
Reuse existing C code with the Android NDK




more: Something about processing images in Android

Android Design for UI Developers

Google I/O 2013 tutorial, Android Design for UI Developers:

In this tutorial video, will explore the arsenal of tools available to Android UI engineers that let developers implement some of these important guidelines, including responsive design with multi-pane layouts, metrics and layout grids, and core navigation components.

Android Studio 0.2.11 Released

Download and Read more: Android Studio 0.2.11 Released.

Convert Bitmap to gray-scale with ColorMatrix

To convert Bitmap to gray-scale, we can apply ColorMatrix with the following matrix:

   //Array to generate Gray-Scale image
float[] GrayArray = {
0.213f, 0.715f, 0.072f, 0.0f, 0.0f,
0.213f, 0.715f, 0.072f, 0.0f, 0.0f,
0.213f, 0.715f, 0.072f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
};

Convert Bitmap to gray-scale with ColorMatrix


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.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity {

Button btnLoadImage;
ImageView imageResult;

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);

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));
loadGrayBitmap(bitmapMaster);

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

break;
}
}
}

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

//Array to generate Identity image
float[] IdentityArray = {
1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
};

//Array to generate Gray-Scale image
float[] GrayArray = {
0.213f, 0.715f, 0.072f, 0.0f, 0.0f,
0.213f, 0.715f, 0.072f, 0.0f, 0.0f,
0.213f, 0.715f, 0.072f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
};

ColorMatrix colorMatrixGray = new ColorMatrix(GrayArray);

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

Bitmap bitmapResult = Bitmap
.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvasResult = new Canvas(bitmapResult);
Paint paint = new Paint();

ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrixGray);
paint.setColorFilter(filter);
canvasResult.drawBitmap(src, 0, 0, paint);

imageResult.setImageBitmap(bitmapResult);
}
}

}


<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:id="@+id/loadimage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Load Image 1" />

<ImageView
android:id="@+id/result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:background="@android:color/background_dark"
android:scaleType="centerInside" />

</LinearLayout>


download filesDownload the files.

download filesDownload and try the APK.

Remark: This exercise aim to demonstrate the matrix. Actually you can setSaturation(0) of  ColorMatrix to do the same effect.



more: Something about processing images in Android

Enable Developer Options for devices with Android 4.2 and higher

On devices running Android 4.2 and higher, the Developer options is hidden by default. To enable Developer Options, go to Settings > About phone and tap Build number seven times, the detail steps may various depends on model.

Here is the steps to enable Developer Options on HTC One X running Android 4.2.2:

- Open Settings, select About.


- Open Software information


- Open More


- Tap on Build number 7 times


- You are now a developer!
- The Developer Options will be in Settings.