Sunday, August 29, 2010

A simple Home Screen App Widget to get Date/Time.

A simple Home Screen App Widget to get Date/Time.

In former exercise, "A dummy Android Home Screen App Widget" without any function have been implemented. Here, we add some code in the onUpdate() method to get and show the date/time on home screen in 30 minutes interval.

A simple Home Screen App Widget to get Date/Time.

Bascically the structure is same as the exercise of "Create a dummy Android Home Screen App Widget".

Modify android:updatePeriodMillis to "1800000" in /res/xml/hellowidgetproviderinfo.xml. Because "updatePeriodMillis will not be delivered more than once every 30 minutes".

Modify /res/layout/hellowidget_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/widgettext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
/>
</LinearLayout>


Modify HelloWidgetProvider.java to override methods onDeleted(), onDisabled(), onEnabled(), and mainly in onUpdate().
package com.exercise.HelloWidget;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.widget.RemoteViews;
import android.widget.Toast;

public class HelloWidgetProvider extends AppWidgetProvider {

private SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy hh:mm:ss a");
String strWidgetText = "";

@Override
public void onDeleted(Context context, int[] appWidgetIds) {
// TODO Auto-generated method stub
//super.onDeleted(context, appWidgetIds);
Toast.makeText(context, "onDeleted()", Toast.LENGTH_LONG).show();
}

@Override
public void onDisabled(Context context) {
// TODO Auto-generated method stub
//super.onDisabled(context);
Toast.makeText(context, "onDisabled()", Toast.LENGTH_LONG).show();
}

@Override
public void onEnabled(Context context) {
// TODO Auto-generated method stub
//super.onEnabled(context);
Toast.makeText(context, "onEnabled()", Toast.LENGTH_LONG).show();
}

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
// TODO Auto-generated method stub

String currentTime = formatter.format(new Date());
strWidgetText = strWidgetText + "\n" + currentTime;

RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.hellowidget_layout);
updateViews.setTextViewText(R.id.widgettext, strWidgetText);
appWidgetManager.updateAppWidget(appWidgetIds, updateViews);

super.onUpdate(context, appWidgetManager, appWidgetIds);
Toast.makeText(context, "onUpdate()", Toast.LENGTH_LONG).show();

}
}
CORRECTION@2010-10-03: The following statement should be moved to the first inside onUpdate() method.
super.onUpdate(context, appWidgetManager, appWidgetIds);

Download the files.

next: A simple Home Screen App Widget with configure activity

Related Article:
- Home Screen Battery Widget


minimum android:updatePeriodMillis

According to Android's document of AppWidgetProviderInfo, updatePeriodMillis define how often, in milliseconds, that this AppWidget wants to be updated.

Updates requested with updatePeriodMillis will not be delivered more than once every 30 minutes.

Ref: public int updatePeriodMillis in AppWidgetProviderInfo.

If you want to implement App Widget with higher rate, reference "App Widget using Alarm Manager".

Tuesday, August 24, 2010

Create a dummy Android Home Screen App Widget

In this exercise, a dummy home screen app widget will be described; to show the simpliest element of a ndroid app widget.

Android Home Screen App Android

- Create a new project of ndroid application as normal, HelloWidget.

- Modify AndroidManifest.xml to have a receiver, with name of "HelloWidgetProvider", under Appliation.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.exercise.HelloWidget"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".HelloWidget"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="HelloWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/hellowidgetproviderinfo" />
</receiver>
</application>
<uses-sdk android:minSdkVersion="4" />

</manifest>
The <receiver> element requires the android:name attribute, which specifies the AppWidgetProvider used by the App Widget.

The <intent-filter> element must include an <action> element with the android:name attribute. This attribute specifies that the AppWidgetProvider accepts the ACTION_APPWIDGET_UPDATE broadcast.

The <meta-data> element specifies the AppWidgetProviderInfo resource and requires the following attributes:

* android:name - Specifies the metadata name. Use android.appwidget.provider to identify the data as the AppWidgetProviderInfo descriptor.
* android:resource - Specifies the AppWidgetProviderInfo resource location.


- Create a new folder /res/xml, create a new hellowidgetproviderinfo.xml
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="146dp"
android:minHeight="72dp"
android:updatePeriodMillis="10000"
android:initialLayout="@layout/hellowidget_layout"
>
</appwidget-provider>
It define the AppWidgetProviderInfo object in an XML resource using a single <appwidget-provider>, include the essential qualities of an App Widget, such as its minimum layout dimensions, its initial layout resource, how often to update the App Widget, and (optionally) a configuration Activity to launch at create-time.


- Create a layout file /res/layout/hellowidget_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
</LinearLayout>
It's the layout of the widget. In this dummy exercisse, just copy the content of the auto-generated layout, main.xml.


- Create a class HelloWidgetProvider.java extends AppWidgetProvider. With nothing inside.
package com.exercise.HelloWidget;

import android.appwidget.AppWidgetProvider;

public class HelloWidgetProvider extends AppWidgetProvider {

}
It do nothing at all.


Now you can build and Install the application as normal, then close it after started. It's not own target in this exercise.

- Add the HelloWidget on Home Screen, as describe in article "Home Screen App Widget". It's a dummy widget without any function, just show how to create a app widget.

Download the files.


Related Article:
minimum android:updatePeriodMillis
A simple Home Screen App Widget to get Date/Time



Sunday, August 22, 2010

Home Screen App Widget

App Widgets are miniature application views that can be embedded in other applications (such as the Home screen) and receive periodic updates. These views are referred to as Widgets in the user interface. For example; a clock, a music player, a picture frame, the Google search bar...etc.

What is widget

How to add a App Widget on Home Screen

1 Touch & hold an empty location on a Home screen.

2 Touch Widgets in the Add to Home screen menu.
To add a widget on Home Screen

3 Touch the widget you want in the Choose widget menu.
Choose the widget to add

4. The Widget will be added on Home Screen.
App Widget is added

How to delete a App Widget on Home Screen

1. Touch & hold the widget on Home screen for a moment, a Trash will appear on the bottom of Home Screen.

2. Hold & move the widget over the trash, and release. The widget will deleted.
Delete a App Widget

Wednesday, August 18, 2010

Implement a Simple Horizontal Indicator using SensorManager and SensorEventListener

In the former articles, "Detect rotation around X, Y & Z axis, using SensorManager and SensorEventListener" and "Implement a Simple Compass using SensorManager and SensorEventListener" have been describe. In this article, I will show how to implement a Horizontal Indicator.

A point float on the screen to indicate horizontal of the phone.

a Simple Horizontal Indicator

Create a custom view, HorizontalView.java, extends View. It display the drawing of our indicator.
package com.exercise.AndroidHorizontal;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

public class HorizontalView extends View {

private float pitch = 0, roll = 0;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private boolean firstDraw;
final float radiusPt = (float)3;

public HorizontalView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}

public HorizontalView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}

public HorizontalView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}

private void init(){

paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(Color.WHITE);
paint.setTextSize(20);

firstDraw = true;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
}

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub

int cxPlan = getMeasuredWidth()/2;
int cyPlan = getMeasuredHeight()/2;

float fullLength, halfLength, ptPerDegree;

if(cxPlan > cyPlan){
fullLength = (float)(getMeasuredHeight() * 0.9);

}
else{
fullLength = (float)(getMeasuredWidth() * 0.9);
}
halfLength = fullLength/2;
ptPerDegree = fullLength/360;

canvas.drawRect(cxPlan-halfLength, cyPlan-halfLength,
cxPlan+halfLength, cyPlan+halfLength, paint);

canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), paint);

if(!firstDraw){
float yPt = cyPlan + (pitch * ptPerDegree);
float xPt = cxPlan + (roll * ptPerDegree);
canvas.drawCircle(xPt, yPt, radiusPt, paint);
}
}

public void updateHorizontal(float tPitch, float tRoll)
{
firstDraw = false;
pitch = tPitch;
roll = tRoll;
invalidate();
}
}


Modify the layout file, main.xml, to add HorizontalView.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<TextView
android:id="@+id/textpitch"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/textroll"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<view
class="com.exercise.AndroidHorizontal.HorizontalView"
android:id="@+id/myhorizontalview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>


Modify the main code, AndroidHorizontal.java, to handle SensorManager and SensorEventListener.
package com.exercise.AndroidHorizontal;

import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;

public class AndroidHorizontal extends Activity {

private static SensorManager mySensorManager;
private boolean sersorrunning;
private HorizontalView myHorizontalView;
private TextView textviewPitch, textviewRoll;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

myHorizontalView = (HorizontalView)findViewById(R.id.myhorizontalview);
textviewPitch = (TextView)findViewById(R.id.textpitch);
textviewRoll = (TextView)findViewById(R.id.textroll);

mySensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
List<Sensor> mySensors = mySensorManager.getSensorList(Sensor.TYPE_ORIENTATION);

if(mySensors.size() > 0){
mySensorManager.registerListener(mySensorEventListener, mySensors.get(0), SensorManager.SENSOR_DELAY_NORMAL);
sersorrunning = true;
Toast.makeText(this, "Start ORIENTATION Sensor", Toast.LENGTH_LONG).show();
}
else{
Toast.makeText(this, "No ORIENTATION Sensor", Toast.LENGTH_LONG).show();
sersorrunning = false;
finish();
}
}

private SensorEventListener mySensorEventListener = new SensorEventListener(){

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub

}

@Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub

textviewPitch.setText("Pitch: " + String.valueOf(event.values[1]));
textviewRoll.setText("Roll: " + String.valueOf(event.values[2]));

myHorizontalView.updateHorizontal(
(float)event.values[1], (float)event.values[2]);
}

};

@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();

if(sersorrunning){
mySensorManager.unregisterListener(mySensorEventListener);
}
}


}


Modify AndroidManifest.xml to disable the auto-rotate feature, otherwise it will point to wrong direction.

Download the files.



Tuesday, August 17, 2010

ListPreference

Compare with the old exercise "Preferences and SharedPreferences" and "EditTextPreference", ListPreference is little bit complicate.

ListPreference

Create a XML file arrays.xml in the folder /res/values/, to define the selection of the list. listDisplayWord define the words to be displayed, listReturnValue define the return value which will be used later.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="listDisplayWord">
 <item>Option 1</item>
 <item>Option 2</item>
 <item>Option 3</item>
</string-array>
<string-array name="listReturnValue">
 <item>1 is selected</item>
 <item>2 is selected</item>
 <item>3 is selected</item>
</string-array>
</resources>


Create a preferences.xml in the folder /res/xml/
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
 <ListPreference
  android:title="List Preference"
  android:summary="Select the option of the list"
  android:key="listPref"
  android:entries="@array/listDisplayWord"
  android:entryValues="@array/listReturnValue" />
</PreferenceScreen>


Create SetPreferences.java
package com.exercise.AndroidListPreference;
import com.exercise.AndroidListPreference.R;

import android.os.Bundle;
import android.preference.PreferenceActivity;

public class SetPreferences extends PreferenceActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  addPreferencesFromResource(R.xml.preferences);
 }
}


Modify main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >
<TextView 
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="@string/hello"
   />
<TextView 
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="Preferences:"
   />
<TextView
   android:id="@+id/list_pref"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   />
<Button
 android:id="@+id/setpreference"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="Set Preference"
 />
</LinearLayout>


Main code
package com.exercise.AndroidListPreference;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class AndroidListPreference extends Activity {
 
 TextView myListPref;
 
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);
       myListPref = (TextView)findViewById(R.id.list_pref);
       Button buttonSetPreference = (Button)findViewById(R.id.setpreference);
      
       buttonSetPreference.setOnClickListener(new Button.OnClickListener(){

   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    startActivity(new Intent(AndroidListPreference.this, SetPreferences.class));
   }});
   }

 @Override
 protected void onResume() {
  // TODO Auto-generated method stub
  super.onResume();
  Toast.makeText(this, "onResume", Toast.LENGTH_LONG).show();
  SharedPreferences myPreference=PreferenceManager.getDefaultSharedPreferences(this);
  String myListPreference = myPreference.getString("listPref", "default choice");
  myListPref.setText(myListPreference);
 }
}


Also have to modify AndroidManifest.xml to include SetPreferences.java
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.exercise.AndroidListPreference"
     android:versionCode="1"
     android:versionName="1.0">
   <application android:icon="@drawable/icon" android:label="@string/app_name">
       <activity android:name=".AndroidListPreference"
                 android:label="@string/app_name">
           <intent-filter>
               <action android:name="android.intent.action.MAIN" />
               <category android:name="android.intent.category.LAUNCHER" />
           </intent-filter>
       </activity>
  <activity android:name=".SetPreferences" />
   </application>
   <uses-sdk android:minSdkVersion="4" />

</manifest>


Download the files.

For Android 3.0 or higher, you should consider PreferenceFragment with ListPreference.


Monday, August 16, 2010

Convert int to Extended ASCII

In my old exercise "ListView with more items on each entry, using SimpleAdapter", convertion of int to ASCII have been introduced:

//i is the int to be converted
byte[] data = {(byte) i};
CharSequence strSymbol = EncodingUtils.getAsciiString(data);



The follwing code show how to convert from int (0x80~0xFF) to extended ASCII of charset "windows-1252", using org.apache.http.util.EncodingUtils.

//i is the int to be converted
byte[] data = {(byte) i};
CharSequence strSymbol = EncodingUtils.getString(data, "windows-1252");





Sunday, August 15, 2010

How to add a linkable text in Dialog

It's a example to add a linkable text in a dialog, using Linkify.

linkable text in Dialog

 private void openOptionsMySiteDialog()
{

final SpannableString stMyWeb = new SpannableString("http://android-er.blogspot.com/");
Linkify.addLinks(stMyWeb, Linkify.ALL);

final AlertDialog aboutDialog = new AlertDialog.Builder(MyActivity.this)
.setMessage(stMyWeb)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}})
.create();

aboutDialog.show();

((TextView)aboutDialog.findViewById(android.R.id.message))
.setMovementMethod(LinkMovementMethod.getInstance());

}

Friday, August 13, 2010

Implement a Simple Compass using SensorManager and SensorEventListener

Refer to the last exercise "Detect rotation around X, Y & Z axis, using SensorManager and SensorEventListener", Azimuth can be used to implement compass.

Simple Compass SensorManager and SensorEventListener

Create a custom view, MyCompassView, extends View. It display the drawing of our compass.
MyCompassView.java
package com.exercise.AndroidCompass;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

public class MyCompassView extends View {

private float direction = 0;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private boolean firstDraw;

public MyCompassView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}

public MyCompassView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}

public MyCompassView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}

private void init(){

paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(Color.WHITE);
paint.setTextSize(30);

firstDraw = true;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
}

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub

int cxCompass = getMeasuredWidth()/2;
int cyCompass = getMeasuredHeight()/2;
float radiusCompass;

if(cxCompass > cyCompass){
 radiusCompass = (float) (cyCompass * 0.9);
}
else{
 radiusCompass = (float) (cxCompass * 0.9);
}
canvas.drawCircle(cxCompass, cyCompass, radiusCompass, paint);
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), paint);

if(!firstDraw){

 canvas.drawLine(cxCompass, cyCompass,
   (float)(cxCompass + radiusCompass * Math.sin((double)(-direction) * 3.14/180)),
   (float)(cyCompass - radiusCompass * Math.cos((double)(-direction) * 3.14/180)),
   paint);

 canvas.drawText(String.valueOf(direction), cxCompass, cyCompass, paint);
}

}

public void updateDirection(float dir)
{
firstDraw = false;
direction = dir;
invalidate();
}

}


Modify the layout file, main.xml, to add MyCompassView.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 >
<TextView
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="@string/hello"
 />
<view
class="com.exercise.AndroidCompass.MyCompassView"
android:id="@+id/mycompassview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>


Modify the main code, AndroidCompass.java, to handle SensorManager and SensorEventListener.
package com.exercise.AndroidCompass;

import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.Toast;

public class AndroidCompass extends Activity {

private static SensorManager mySensorManager;
private boolean sersorrunning;
private MyCompassView myCompassView;

 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.main);
  
     myCompassView = (MyCompassView)findViewById(R.id.mycompassview);
  
     mySensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
     List<Sensor> mySensors = mySensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
  
     if(mySensors.size() > 0){
      mySensorManager.registerListener(mySensorEventListener, mySensors.get(0), SensorManager.SENSOR_DELAY_NORMAL);
      sersorrunning = true;
      Toast.makeText(this, "Start ORIENTATION Sensor", Toast.LENGTH_LONG).show();
    
     }
     else{
      Toast.makeText(this, "No ORIENTATION Sensor", Toast.LENGTH_LONG).show();
      sersorrunning = false;
      finish();
     }
 }

 private SensorEventListener mySensorEventListener = new SensorEventListener(){

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
 // TODO Auto-generated method stub

}

@Override
public void onSensorChanged(SensorEvent event) {
 // TODO Auto-generated method stub
 myCompassView.updateDirection((float)event.values[0]);
}
 };

@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();

if(sersorrunning){
 mySensorManager.unregisterListener(mySensorEventListener);
}
}

}


Modify AndroidManifest.xml to disable the auto-rotate feature, otherwise it will point to wrong direction.

download filesDownload the files.

Related Article:
Implement a Simple Horizontal Indicator using SensorManager and SensorEventListener

Thursday, August 12, 2010

Test build for Android-x86 2.2 (Froyo-x86) on virtual machine is announced

The iso is intended for vm only (virtual box, qemu, vmware, ...). It may not work on any other real x86 machine.

Android-x86 2.2 (Froyo-x86) on virtual machine
Android-x86 2.2 (Froyo-x86) on virtual machine
Android-x86 2.2 (Froyo-x86) on virtual machine

Key Features

* Kernel 2.6.32.9
* Audio support for ICH AC97 and SB16
* Ethernet support
* Mouse cursor
* Persistent mode
* Some 3rd party apps updated

Details>> http://www.android-x86.org/releases/build-20100812

But the Mouse cursor is too slow to be used! as stated in the Known issues section. Looking for the next version to solve this problem.

Android-x86 is a project to port Android open source project to different x86 platforms, - Run Android on Your PC.

Wednesday, August 11, 2010

HTC released kernel source code of EVO 4G, Droid Incredible, Wildfire, Aria, and also Nexus One system image.

The HTC Developer Center is a place for developers to obtain essential resources to help you in developing great applications on HTC's Android and Windows Mobile phones.

You can download Kernel Source Code and Binaries for HTC Android Phones from HTC Developer Center.

Monday, August 9, 2010

Detect rotation around X, Y & Z axis, using SensorManager and SensorEventListener

SensorManager is a class that lets you access the device's sensors. SensorEventListener is used for receiving notifications from the SensorManager when sensor values have changed.



The method onSensorChanged(SensorEvent event) of SensorEventListener will be called when sensor values have changed. The rotation in degree can be retrieved from event.values[0], event.values[1] and event.values[2].

event.values[0]: azimuth, rotation around the Z axis.
event.values[1]: pitch, rotation around the X axis.
event.values[2]: roll, rotation around the Y axis.

Modify main.xml to have three TextView to display azimuth, pitch and roll.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<TextView
android:id="@+id/textazimuth"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Azimuth: "
/>
<TextView
android:id="@+id/textpitch"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Pitch: "
/>
<TextView
android:id="@+id/textroll"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Roll: "
/>
</LinearLayout>


AndroidSensorEventListener.java
package com.exercise.AndroidSensorEventListener;

import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;

public class AndroidSensorEventListener extends Activity {

TextView textviewAzimuth, textviewPitch, textviewRoll;
private static SensorManager mySensorManager;
private boolean sersorrunning;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textviewAzimuth = (TextView)findViewById(R.id.textazimuth);
textviewPitch = (TextView)findViewById(R.id.textpitch);
textviewRoll = (TextView)findViewById(R.id.textroll);

mySensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
List<Sensor> mySensors = mySensorManager.getSensorList(Sensor.TYPE_ORIENTATION);

if(mySensors.size() > 0){
mySensorManager.registerListener(mySensorEventListener, mySensors.get(0), SensorManager.SENSOR_DELAY_NORMAL);
sersorrunning = true;
Toast.makeText(this, "Start ORIENTATION Sensor", Toast.LENGTH_LONG).show();
}
else{
Toast.makeText(this, "No ORIENTATION Sensor", Toast.LENGTH_LONG).show();
sersorrunning = false;
finish();
}

}

private SensorEventListener mySensorEventListener = new SensorEventListener() {

@Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub

textviewAzimuth.setText("Azimuth: " + String.valueOf(event.values[0]));
textviewPitch.setText("Pitch: " + String.valueOf(event.values[1]));
textviewRoll.setText("Roll: " + String.valueOf(event.values[2]));

}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub

}
};

@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();

if(sersorrunning){
mySensorManager.unregisterListener(mySensorEventListener);
Toast.makeText(AndroidSensorEventListener.this, "unregisterListener", Toast.LENGTH_SHORT).show();
}
}
}


Download the files.

Related Article:
OrientationEventListener, detect orientation change from the SensorManager.
Implement a Simple Compass using SensorManager and SensorEventListener
Implement a Simple Horizontal Indicator using SensorManager and SensorEventListener



Sunday, August 8, 2010

OrientationEventListener, detect orientation change from the SensorManager.

android.view.OrientationEventListener is a Helper class for receiving notifications from the SensorManager when the orientation of the device has changed.

[Note: The another class OrientationListener is deprecated.]




The method onOrientationChanged(int orientation) will be called when the orientation of the device has changed. orientation parameter is in degrees, ranging from 0 to 359. orientation is 0 degrees when the device is oriented in its natural position, 90 degrees when its left side is at the top, 180 degrees when it is upside down, and 270 degrees when its right side is to the top. ORIENTATION_UNKNOWN is returned when the device is close to flat and the orientation cannot be determined.

Modify main.xml to have a TextView to display the updated orientation.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<TextView
android:id="@+id/textorientation"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Orientation: "
/>
</LinearLayout>


AndroidOrientationSensor.java
package com.exercise.AndroidOrientationSensor;

import android.app.Activity;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.OrientationEventListener;
import android.widget.TextView;
import android.widget.Toast;

public class AndroidOrientationSensor extends Activity{

TextView textviewOrientation;
OrientationEventListener myOrientationEventListener;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textviewOrientation = (TextView)findViewById(R.id.textorientation);

myOrientationEventListener
= new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL){

@Override
public void onOrientationChanged(int arg0) {
// TODO Auto-generated method stub
textviewOrientation.setText("Orientation: " + String.valueOf(arg0));
}};

if (myOrientationEventListener.canDetectOrientation()){
Toast.makeText(this, "Can DetectOrientation", Toast.LENGTH_LONG).show();
myOrientationEventListener.enable();
}
else{
Toast.makeText(this, "Can't DetectOrientation", Toast.LENGTH_LONG).show();
finish();
}


}

@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
myOrientationEventListener.disable();
}
}

Download the files.

Related Article: Detect rotation around X, Y & Z axis, using SensorManager and SensorEventListener

Friday, August 6, 2010

How to disable the auto-rotate feature?

In some case, we want our app run in portrait mode only, so we have to disable the auto-rotate feature. Simple add the statement android:screenOrientation="portrait" in your AndroidManifest.xml, inside <activity>

<activity android:name=".MyActivity"
android:label="@string/app_name"
android:screenOrientation="portrait">

Tuesday, August 3, 2010

Developing Android application on HTC Wildfire, under Windows 7

In the article "Developing Android application on real phone", it's described how to develope Android Application on real phone (HTC Wildfire), under Linux Ubuntu.

How about that under Windows 7? I tried to install USB Driver for Windows, follow the instruction from Google. But, the phone cannot be detected, and cannot install the drivers finally.

Recently, HTC release HTC Sync™for HTC Wildfire, for Windows. The application come with all needed driver, include ADB. There are no extra works needed. Just follow the normal steps as described in "Developing Android application on real phone".

please note that you have to enable USB Debugging on phone, when install HTC Sync™for HTC Wildfire.

Tips 1:

If you cannot see the HTC Sync option when you connect your phone to the computer via USB, please follow the

Instructions below:

1. Make sure you select USB Debugging in Settings > Applications > Development before connecting your phone to the computer

2. Connect you Phone to the PC and wait 20 seconds for your phone to install HTC Sync on your phone.

3. Unplug the USB sync cable. Wait for 5 seconds. Reconnect the Phone to the PC using the USB cable.

4. Select “HTC sync” and wait for HTC Sync to recognize your Phone. This process could take up to a minute your first time connecting to the computer.

One more experience I want to point out here:
When the phone is connected to PC, the SD Card will be unmouted from the phone, and redirected to be mounted on PC. Such that if you develope a app on a connected phone, it cannot access the SD Card actually. You have to disconnect the phone from PC to make it run as normal.



Monday, August 2, 2010

EditTextPreference

Further work on last exercise "Preferences and SharedPreferences", a EditTextPreference will be added here.

EditTextPreference

Modify mypreference.xml too add a EditTextPreference
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:key="checkboxvalue"
android:title="Checkbox"
android:defaultValue="true"
android:summary="CheckBoxPreference" />
<EditTextPreference
android:key="edittexvalue"
android:title="EditText"
android:summary="EditTextPreference" />
</PreferenceScreen>


Modify main.xml to have TextView for the EditTextPreference
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button
android:id="@+id/setpreference"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Set Preference"
/>
<TextView
android:id="@+id/checkboxstatus"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/edittextstatus"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>


Modify AndroidPreference.java
package com.exercise.AndroidPreference;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class AndroidPreference extends Activity {

TextView checkBoxStatus, editTextStatus;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Button buttonSetPreference = (Button)findViewById(R.id.setpreference);
checkBoxStatus = (TextView)findViewById(R.id.checkboxstatus);
editTextStatus = (TextView)findViewById(R.id.edittextstatus);

buttonSetPreference.setOnClickListener(new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
startActivity(new Intent(AndroidPreference.this, SetPreference.class));
}});
}

@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
Toast.makeText(this, "onResume", Toast.LENGTH_LONG).show();

SharedPreferences myPreference=PreferenceManager.getDefaultSharedPreferences(this);
checkBoxStatus.setText("CheckBox Status: " + myPreference.getBoolean("checkboxvalue", true));
editTextStatus.setText("EditText Status: " + myPreference.getString("edittexvalue", ""));
}
}



Download the files.

Sunday, August 1, 2010

Preferences and SharedPreferences

Android provide Preferences and SharedPreferences classes, which provides a mechanism to store and access configuration data in a hierarchical way. Such that apps can keep preferences after apps closed and re-started.

Preferences and SharedPreferences

It's a simple example to show how to use Preferences and SharedPreferences classes. If user check/uncheck the CheckBox on the main activity, the setting will not be saved after the app exited (by BACK button), but the status in the SetPreference.java will be saved, it will be kept after app re-started.

- Create a XML file in /res/xml/ to define our PreferenceScreen; mypreference.xml in my example.
mypreference.xml
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:key="checkbox"
android:title="Checkbox"
android:defaultValue="true"
android:summary="Change The CheckBox Status here, it will be saved in Preference" />
</PreferenceScreen>


- Create a new Activity (SetPreference.java in my example) extends PreferenceActivity, to access the XML file.
SetPreference.java
package com.exercise.AndroidPreference;

import android.os.Bundle;
import android.preference.PreferenceActivity;

public class SetPreference extends PreferenceActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
 // TODO Auto-generated method stub
 super.onCreate(savedInstanceState);
 addPreferencesFromResource(R.xml.mypreference);
}

}


- Modify main.xml to add a button to involve the new Activity.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button
android:id="@+id/setpreference"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Set Preference"
/>
<CheckBox
android:id="@+id/checkbox"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Check CheckBox status here will not be saved, it will be lost once activity exit."
/>
</LinearLayout>


- Call the new class from our main java code.
package com.exercise.AndroidPreference;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.Toast;

public class AndroidPreference extends Activity {

CheckBox checkBox;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Button buttonSetPreference = (Button)findViewById(R.id.setpreference);
    checkBox = (CheckBox)findViewById(R.id.checkbox);

    buttonSetPreference.setOnClickListener(new Button.OnClickListener(){

  @Override
  public void onClick(View arg0) {
   // TODO Auto-generated method stub
   startActivity(new Intent(AndroidPreference.this, SetPreference.class));
  }});
}

@Override
protected void onResume() {
 // TODO Auto-generated method stub
 super.onResume();
 Toast.makeText(this, "onResume", Toast.LENGTH_LONG).show();

 SharedPreferences myPreference=PreferenceManager.getDefaultSharedPreferences(this);
 checkBox.setChecked(myPreference.getBoolean("checkbox", true));
}
}


- Modify AndroidManifest.xml to add the new Activity.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.exercise.AndroidPreference"
  android:versionCode="1"
  android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
    <activity android:name=".AndroidPreference"
              android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
 <activity android:name=".SetPreference" />
</application>
<uses-sdk android:minSdkVersion="4" />

</manifest>


Download the files.

Related Article:
EditTextPreference
ListPreference


*** This functionality should now be found in the new PreferenceFragment class.