Wednesday, February 11, 2009

X Y motion

Android's onTouchEvent was giving me some difficulties. I want to increment and decrement my countdown timer based on touch screen input. The user should be able to touch the screen anywhere and move their finger left, right, up or down, and the values should change in a logical way. I discovered I had to introduce a certain scaling factor in order to prevent the tiny increments and decrements from canceling each other out effectively. The code I came up with computes the delta in X and Y coordinates and only increments or decrements the countdown timer values if the delta is more than a certain amount, in the example the value is 5. You could change this to make the system more or less sensitive. This effectively "understands" the intent of the user's gesture.

Here is my onTouchEvent, it should be fairly self explanatory.

@Override
public boolean onTouchEvent(MotionEvent event) {
float mvX;
float mvY;
boolean chg;
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
startY = event.getY();
startX = event.getX();
break;
case MotionEvent.ACTION_MOVE:
endY = event.getY();
endX = event.getX();
break;
case MotionEvent.ACTION_UP:
endY = event.getY();
endX = event.getX();
break;
default:
return false;
}
chg = false;
mvY = endY - startY;
if(mvY > 5) {
mySecondsTotal += 1;
chg = true;
}
if(mvY < -5) {
mySecondsTotal -= 1;
chg = true;
}
mvX = endX - startX;
if(mvX > 5) {
mySecondsTotal += 1;
chg = true;
}
if(mvX < -5) {
mySecondsTotal -= 1;
chg = true;
}
if (chg == false)
return true;
startY = event.getY();
startX = event.getX();
if (mySecondsTotal < 0)
mySecondsTotal = 0;
Message m = new Message();
m.what = timer.GUIUPDATEIDENTIFIER;
this.myYogaViewUpdateHandler.sendMessage(m);
return true;
}

Monday, February 9, 2009

Using a RadioGroup

Set up your RadioGroup and RadioButtons in your xml layout:


<radiogroup id="@+id/group1" layout_width="fill_parent" layout_height="wrap_content" orientation="horizontal">
<radiobutton id="@+id/radio1" text="Bell" layout_width="wrap_content" layout_height="wrap_content">
</radiobutton>
<radiobutton id="@+id/radio2" text="Crystal" layout_width="wrap_content" layout_height="wrap_content">
</radiobutton>
<radiobutton id="@+id/radio3" text="Gong" layout_width="wrap_content" layout_height="wrap_content">
</radiobutton>
</radiogroup>


Save your preferences


int chime = chimes.getCheckedRadioButtonId();


At first nothing is selected and getCheckedRadioButtonId will return a value of -1, so you might want to test for this condition when getting your saved preferences. Otherwise you'll get the Unique ID of the checked Radio Button which you need to test using R.id.


int chime = prefs.getInt(PREF_CHIME, R.id.radio1);
if (chime < 1)
chime = R.id.radio1;
chimes.check(chime);


Handle the options:


int chime = prefs.getInt(preferences.PREF_CHIME, R.raw.bell);
switch(chime){
case R.id.radio1: {
mp = MediaPlayer.create(timer.this, R.raw.bell);
break;
}
case R.id.radio2: {
mp = MediaPlayer.create(timer.this, R.raw.crystal);
break;
}
case R.id.radio3: {
mp = MediaPlayer.create(timer.this, R.raw.gong);
break;
}
default:
mp = MediaPlayer.create(timer.this, R.raw.bell);
break;
}
try {
mp.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

Saturday, January 31, 2009

T-Mobile 3G Problems

Turns out that when you download an Adroid APK file from a web page and you're on the T-Mobile 3G network you don't always get the whole APK file. You might need to switch to a Wireless network connection to get a good download.

If you're trying to download a third party APK file like the ones I develop and you get an odd error that the package you're trying to install is replacing an existing package and this is followed by an installation failed message, you could be seeing this problem.

Some reports indicate you might also be able to get around this by switching to 2G mode, but I haven't tried it.

Here is another resource

Way to go T-Mobile!

Webkit About box

This is kind of overkill for an About dialog, but the neat thing is you can click on the URL and go right to the web page. Hitting the back button returns to your application so it is very smooth


public class about extends Activity {
WebView aboutText;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.about);
aboutText = (WebView)findViewById(R.id.about_text);
String str = "<I>Yoga Timer</I><HR/>Version 1.4<BR/>" +
"<P>Patterns multiply the starting value to set separate durations for the four parts of the breath: <UL>" +
"<LI>Inhalation (Pooraka)<LI>Retention (Abhyantar Kumbhaka)<LI>Exhalation (Rechaka)<LI>Suspension (Bahya Kumbhaka)</UL>" +
"<P>Check for new versions here <A href=http://cubicware.com/>CUBICWARE.COM</A>";
aboutText.loadData(str, "text/html", "utf-8");
Button okButton = (Button) findViewById(R.id.okButton);
okButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
finish();
}
});
}
}

Android notifications

This is a work in progress. I don't think the light notification is working yet.


if (notifyVibrate){
Notification notification = new Notification();
notification.vibrate = new long[] { 100, 250, 100, 500};
nm.notify(NOTIFY_ID, notification);
}
if (notifyLight) {
Notification notification = new Notification();
notification.ledARGB = 0xFFFF5171;
notification.ledOnMS = 100;
notification.ledOffMS = 100;
notification.flags = Notification.FLAG_SHOW_LIGHTS;
nm.notify(NOTIFY_ID, notification);
}
if (notifyToast) {
Toast toast = Toast.makeText(timer.this , R.string.notification_text, Toast.LENGTH_SHORT);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}
if (notifySound) {
mp.play(timer.this, Settings.System.DEFAULT_NOTIFICATION_URI, false, AudioManager.STREAM_ALARM);
}

Signing Android packages using Eclipse external tools commands.

Here is how I got this to work. You might be able to integrate it into Eclipse better but I couldn't because I needed to export to a folder outside of my Eclipse workspace. Might be able to do it into your workspace but I didn't try to figure that out.

First you will need to create your android.keystore using keytool. The easiest way to do this is find the keytool and open a command line session to the directory it is in and then generate your certificate from the command line. It's pretty straightforward.

Create a bat file that looks like the one below.

@echo off
@echo Signing "%1"
C:\SUN\SDK\JDK\bin\jarsigner -verbose -keystore android.keystore "%1" android
if errorlevel 1 goto ERROR
C:\SUN\SDK\JDK\bin\jarsigner -verify "%1"
if errorlevel 1 goto ERROR
goto DONE
:ERROR
@pause
:DONE
@echo on


I created a folder called Deploy someone in my Documents hierarchy and copied this bat file and android.keystore into that folder.

When you want to deploy your application, highlight your Package Name in Eclipse and right click. Select Android Tools/Export Unsigned Package and export into your Deploy directory you created above.

Now open a CMD prompt and find your Deploy folder. Run sign.bat .apk

Now you're ready to upload your signed application to your web space for people to install from.

You can also configure Eclipse to run this bat file as an external program. Just go to Run/External Tools/External Tools Configurations and create a new Program. Call it Sign Android Package or whatever you want, and in the location field point to your bat file. On my system this looks like this

K:\Users\John\Documents\deploy\sign.bat

Set the working directory to the deploy folder

K:\Users\John\Documents\deploy

For the Argment specify your package name with the apk extension:

${project_name}.apk

That's it! Now you can sign your package. Just remember to Export the unsigned package each time you want to deploy your application, and then run this external command to sign it.

Android phones are easy to install applications on, you just click on the file and download it but see my note concerning potential problems downloading package files with T-Mobile's 3G network. Search for the 3g label in this blog.

Code highlighting on blogger

I found this here but thought I'd document it in case it disappears.

<link href="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js"> </script>

<body onload='prettyPrint()'>


<pre class="prettyprint">
... # Your code goes here
</pre>

Android alertdialog from a menu selection

How to pop up a dialog from a menu selection

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case (MENU_ABOUT): {
new AlertDialog.Builder(this)
.setTitle("About Mala Counter")
.setMessage("Version 1.0 from Cubicware.com")
.setPositiveButton(android.R.string.ok, null)
.show();
return true;
}
}
return false;
}