I recently got the fancy Apple earphones for my iPhone GS. Along with the microphone, the earphones include a volume control. But wait ... there's more!!!!
In addition to volume control, you can now skip, fast forward, and rewind all from your headphones. No need to get your iPhone or iPod out of your pocket. Unfortunately, the command listing comes in a thick little booklet that contains about 20 language translations. Not very portable or useful. Therefore, I created the following english cheat sheet and posted it on this site. The page includes a link which allows you to store the cheat sheet offline in a bookmark. Enjoy!
iPhone/iPod Earphone Commands
Monday, 31 May 2010
Sunday, 30 May 2010
CSS Tip: Remove Part of a Border
Often when working with a box thingy, you want a border on 3 sides, but not four. Normally, you would code that with something like this:
Instead of doing this, create a complete border, then eliminate one side. For example:
Now you have a three sided box with the bottom side eliminated. Nice. Shout out to websiteoptimization.com for the tip.
.someBoxyThing{
border-top:1pt solid black;
border-right:1pt solid black;
border-left:1pt solid black;
}
Instead of doing this, create a complete border, then eliminate one side. For example:
.someBoxyThing{
border:1pt solid black;
border-bottom:0px;
}
Now you have a three sided box with the bottom side eliminated. Nice. Shout out to websiteoptimization.com for the tip.
Another exercise of SurfaceView, in a FrameLaout inside another LinearLayout
It's another exercise of using FurfaceView in Android.
In the previous exercises "Android SurfaceView" and "Android SurfaceView, run in Thread with sleep()", the layout was simple a FrameLayout composed of a SurfaceView only, setup using programming code setContentView(R.layout.main).
In this exercise, it's a FrameLayout inside a LinearLayout, together with two buttons. The FrameLayout is composed of a SurfaceView. And the layout is defined in main.xml. Both the MySurfaceView(extends SurfaceView) and the MySurfaceThread(extends Thread) are implemented as separated class. When the application is running, there are two buttons over the FrameLayout with SurfaceView, a dot bounce inside the SurfaceView. User can click the first button to make the another button invisible, to change the dimension of the FrameLayout in run-time, and the SurfaceView change also accordingly.
main.xml
MySurfaceView.java
MySurfaceThread.java
AndroidMergeSurfaceView.java
Download the files.
Further exercise on SurfaceView: SurfaceView overlap with a LinearLayout
In the previous exercises "Android SurfaceView" and "Android SurfaceView, run in Thread with sleep()", the layout was simple a FrameLayout composed of a SurfaceView only, setup using programming code setContentView(R.layout.main).
In this exercise, it's a FrameLayout inside a LinearLayout, together with two buttons. The FrameLayout is composed of a SurfaceView. And the layout is defined in main.xml. Both the MySurfaceView(extends SurfaceView) and the MySurfaceThread(extends Thread) are implemented as separated class. When the application is running, there are two buttons over the FrameLayout with SurfaceView, a dot bounce inside the SurfaceView. User can click the first button to make the another button invisible, to change the dimension of the FrameLayout in run-time, and the SurfaceView change also accordingly.
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">
<Button
android:id="@+id/showhide"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Toggle The Another Button Show/Hide" />
<Button
android:id="@+id/dummy"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="a Button" />
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.exercise.AndroidMergeSurfaceView.MySurfaceView
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</FrameLayout>
</LinearLayout>
MySurfaceView.java
package com.exercise.AndroidMergeSurfaceView;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{
private MySurfaceThread thread;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
int cx, cy, offx, offy;
public MySurfaceView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}
private void init(){
getHolder().addCallback(this);
thread = new MySurfaceThread(getHolder(), this);
setFocusable(true); // make sure we get key events
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(Color.WHITE);
cx = 0;
cy = 0;
offx = 10;
offy = 10;
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.setRunning(true);
thread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
}
catch (InterruptedException e) {
}
}
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
canvas.drawRGB(0, 0, 0);
canvas.drawCircle(cx, cy, 3, paint);
cx += offx;
if (cx > getWidth() || (cx < 0)){
offx *= -1;
cx += offx;
}
cy += offy;
if (cy > getHeight() || (cy < 0)){
offy *= -1;
cy += offy;
}
}
}
MySurfaceThread.java
package com.exercise.AndroidMergeSurfaceView;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class MySurfaceThread extends Thread {
private SurfaceHolder myThreadSurfaceHolder;
private MySurfaceView myThreadSurfaceView;
private boolean myThreadRun = false;
public MySurfaceThread(SurfaceHolder surfaceHolder, MySurfaceView surfaceView) {
myThreadSurfaceHolder = surfaceHolder;
myThreadSurfaceView = surfaceView;
}
public void setRunning(boolean b) {
myThreadRun = b;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(myThreadRun){
Canvas c = null;
try{
c = myThreadSurfaceHolder.lockCanvas(null);
synchronized (myThreadSurfaceHolder){
myThreadSurfaceView.onDraw(c);
}
sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
myThreadSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
AndroidMergeSurfaceView.java
package com.exercise.AndroidMergeSurfaceView;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class AndroidMergeSurfaceView extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonShowHide = (Button)findViewById(R.id.showhide);
final Button buttonDummy = (Button)findViewById(R.id.dummy);
buttonShowHide.setOnClickListener(
new Button.OnClickListener(){
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
if(buttonDummy.getVisibility()==View.VISIBLE){
buttonDummy.setVisibility(View.GONE);
}
else{
buttonDummy.setVisibility(View.VISIBLE);
}
}
}
);
}
}
Download the files.
Further exercise on SurfaceView: SurfaceView overlap with a LinearLayout
It's a bug here!
Pls. refer to the article
"IllegalThreadStateException in LunarLander"
for details.
I'm Sorry about that! (Android Er@2010-06-04)
Wednesday, 26 May 2010
iPad: SimpleNote is the Note App You are Looking For
Ever since I got an iPhone, I have been looking for a replacement for Notes apps. The app only syncs with Mac Mail or Outlook, neither of which I use. What I need is a notes app that can sync to the Net. The app should allow me to add notes from any desktop machine, notebook, phone, or iPad and sync them to all the devices.
Well SimpleNote does that, and it does it very well. Nothing fancy about this app. You just get a box you can type in. The first line is the title, the rest just text.
On the iPad, SimpleNote looks something like this:
The title of your notes on the left. And the text associated with the selected note on the right.
In the iPhone, the interface is simpler. Just click on the note title brings up the note. Here is a snapshot.
The syncing is truly amazing. Just bring up SimpleNote on whatever platform you are using, bing, you have the latest and greatest notes. This is an app everyone should have.
Well SimpleNote does that, and it does it very well. Nothing fancy about this app. You just get a box you can type in. The first line is the title, the rest just text.
On the iPad, SimpleNote looks something like this:
The title of your notes on the left. And the text associated with the selected note on the right.
In the iPhone, the interface is simpler. Just click on the note title brings up the note. Here is a snapshot.
The syncing is truly amazing. Just bring up SimpleNote on whatever platform you are using, bing, you have the latest and greatest notes. This is an app everyone should have.
Tuesday, 25 May 2010
Two view in one FrameLayout
In my previous exercise "Draw a bitmap on View", "Draw something on a Canvas", "Android FaceDetector" and "Custom View with User Interaction", everything is drawn on ONE view. In this exercise, it will be separated in two views. The un-changed bitmap is drawn on View1, and user interaction is drawn on View2. Such that, everytime VIew2.onDraw() will redraw the interactive part only, no need to re-draw the bitmap.
The layout file, main.xml, is modified to use a FrameLayout with two View, cover whole of the screen.
- place a bitmap of 320x480 in /res/drawable/ folder, or using the bitmap in the downloaded files.
- Create two view class extends View
View1.java
View2.java
- Modify main.xml
- AndroidTwoView.java actually no change from the auto-generated.
Download the files.
The layout file, main.xml, is modified to use a FrameLayout with two View, cover whole of the screen.
- place a bitmap of 320x480 in /res/drawable/ folder, or using the bitmap in the downloaded files.
- Create two view class extends View
View1.java
package com.exercise.AndroidTwoView;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
public class View1 extends View {
public View1(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public View1(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public View1(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
@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
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.googlelogo320x480);
canvas.drawBitmap(myBitmap, 0, 0, null);
}
}
View2.java
package com.exercise.AndroidTwoView;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class View2 extends View {
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
float cx = 0, cy =0;
boolean draw = false;
public View2(Context context) {
super(context);
init();
}
public View2(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public View2(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init(){
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(Color.BLUE);
setFocusable(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
if (draw){
canvas.drawCircle(cx, cy, 3, paint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
int action = event.getAction();
if (action==MotionEvent.ACTION_DOWN){
cx = event.getX();
cy = event.getY();
draw = true;
invalidate();
}
return true;
}
}
- Modify main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.exercise.AndroidTwoView.View1
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
<com.exercise.AndroidTwoView.View2
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</FrameLayout>
- AndroidTwoView.java actually no change from the auto-generated.
Download the files.
Android SurfaceView, run in Thread with sleep()
Further works on the last exercise "Android SurfaceView", a call to sleep(500) is introduced in run() of the thread, such that the onDraw() will be called in half second.
In this exercise, there is a point on the screen. When user touch on screen, the point will run from the current position to the touched position, in speed of half the distance per second.
AndroidSurfaceViewUI.java
Download the file.
In this exercise, there is a point on the screen. When user touch on screen, the point will run from the current position to the touched position, in speed of half the distance per second.
AndroidSurfaceViewUI.java
package com.exercise.AndroidSurfaceViewUI;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class AndroidSurfaceViewUI extends Activity {
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private float initX, initY;
private float targetX, targetY;
private boolean drawing = true;
public class MySurfaceThread extends Thread {
private SurfaceHolder myThreadSurfaceHolder;
private MySurfaceView myThreadSurfaceView;
private boolean myThreadRun = false;
public MySurfaceThread(SurfaceHolder surfaceHolder, MySurfaceView surfaceView) {
myThreadSurfaceHolder = surfaceHolder;
myThreadSurfaceView = surfaceView;
}
public void setRunning(boolean b) {
myThreadRun = b;
}
@Override
public void run() {
// TODO Auto-generated method stub
//super.run();
while (myThreadRun) {
Canvas c = null;
try {
c = myThreadSurfaceHolder.lockCanvas(null);
synchronized (myThreadSurfaceHolder) {
myThreadSurfaceView.onDraw(c);
}
sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
myThreadSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{
private MySurfaceThread thread;
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
//super.onDraw(canvas);
if(drawing){
canvas.drawRGB(0, 0, 0);
canvas.drawCircle(initX, initY, 3, paint);
if ((initX==targetX) && (initY==targetY)){
drawing = false;
}
else{
initX = (initX + targetX)/2;
initY = (initY + targetY)/2;
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
//return super.onTouchEvent(event);
int action = event.getAction();
if (action==MotionEvent.ACTION_DOWN){
targetX = event.getX();
targetY = event.getY();
drawing = true;
}
return true;
}
public MySurfaceView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}
private void init(){
getHolder().addCallback(this);
thread = new MySurfaceThread(getHolder(), this);
setFocusable(true); // make sure we get key events
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(Color.WHITE);
initX = targetX = 0;
initY = targetY = 0;
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.setRunning(true);
thread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
MySurfaceView mySurfaceView = new MySurfaceView(this);
setContentView(mySurfaceView);
}
}
Download the file.
Monday, 24 May 2010
Google Needs to be More Focused
John C Dvorak thinks Google needs to be more focused. I agree. Right now they are making a lot of money, but they seem to want to dabble in everything. What sets Google apart? Internet Search? Contextual advertising? Cloud Computing?
Maybe Google just makes the Net easier to use? Much like Apple has made the PC and the phone easier to use. Google has been a very positive force on the Net so I hope they figure it out.
Maybe Google just makes the Net easier to use? Much like Apple has made the PC and the phone easier to use. Google has been a very positive force on the Net so I hope they figure it out.
Sunday, 23 May 2010
Android SurfaceView
It's a SurfaceView variation from the last exercise "Custom View with User Interaction".
- Implement a new class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback.
- Implement the surfaceCreated(), surfaceDestroyed(), surfaceChanged() methods for SurfaceHolder.Callback.
- Implement a Thread for our SurfaceView.
- In SurfaceView's constructor, add the SurfaceView to SurfaceHolder for a callback, and create the Thread.
getHolder().addCallback(this);
thread = new MySurfaceThread(getHolder(), this);
- Modify the run() method of the Thread
(In the View version in "Custom View with User Interaction", the view is forced to re-draw by invalidate() method, so the screen will be cleared. In this SurfaceView version, the onDraw() method is called inside thread's Run() method, so the drawing on the original canvas will not be cleared.)
Download the file.
next: Android SurfaceView, run in Thread with sleep()
- Implement a new class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback.
- Implement the surfaceCreated(), surfaceDestroyed(), surfaceChanged() methods for SurfaceHolder.Callback.
- Implement a Thread for our SurfaceView.
- In SurfaceView's constructor, add the SurfaceView to SurfaceHolder for a callback, and create the Thread.
getHolder().addCallback(this);
thread = new MySurfaceThread(getHolder(), this);
- Modify the run() method of the Thread
package com.exercise.AndroidSurfaceViewUI;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class AndroidSurfaceViewUI extends Activity {
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private float initX, initY, radius;
private boolean drawing = false;
public class MySurfaceThread extends Thread {
private SurfaceHolder myThreadSurfaceHolder;
private MySurfaceView myThreadSurfaceView;
private boolean myThreadRun = false;
public MySurfaceThread(SurfaceHolder surfaceHolder, MySurfaceView surfaceView) {
myThreadSurfaceHolder = surfaceHolder;
myThreadSurfaceView = surfaceView;
}
public void setRunning(boolean b) {
myThreadRun = b;
}
@Override
public void run() {
// TODO Auto-generated method stub
//super.run();
while (myThreadRun) {
Canvas c = null;
try {
c = myThreadSurfaceHolder.lockCanvas(null);
synchronized (myThreadSurfaceHolder) {
myThreadSurfaceView.onDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
myThreadSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{
private MySurfaceThread thread;
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
//super.onDraw(canvas);
if(drawing){
canvas.drawCircle(initX, initY, radius, paint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
//return super.onTouchEvent(event);
int action = event.getAction();
if (action==MotionEvent.ACTION_MOVE){
float x = event.getX();
float y = event.getY();
radius = (float) Math.sqrt(Math.pow(x-initX, 2) + Math.pow(y-initY, 2));
}
else if (action==MotionEvent.ACTION_DOWN){
initX = event.getX();
initY = event.getY();
radius = 1;
drawing = true;
}
else if (action==MotionEvent.ACTION_UP){
drawing = false;
}
return true;
}
public MySurfaceView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}
private void init(){
getHolder().addCallback(this);
thread = new MySurfaceThread(getHolder(), this);
setFocusable(true); // make sure we get key events
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(Color.WHITE);
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.setRunning(true);
thread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
MySurfaceView mySurfaceView = new MySurfaceView(this);
setContentView(mySurfaceView);
}
}
(In the View version in "Custom View with User Interaction", the view is forced to re-draw by invalidate() method, so the screen will be cleared. In this SurfaceView version, the onDraw() method is called inside thread's Run() method, so the drawing on the original canvas will not be cleared.)
Download the file.
next: Android SurfaceView, run in Thread with sleep()
It's a bug here!
Pls. refer to the article
"IllegalThreadStateException in LunarLander"
for details.
I'm Sorry about that! (Android Er@2010-06-04)
Saturday, 22 May 2010
Custom View with User Interaction
In my previous exercise "Draw a bitmap on View", "Draw something on a Canvas" and even "Android FaceDetector", the application output is drawn on View in onDraw method in application starting once only; without any interaction with user. In this exercise, a custom View with user interaction will be implemented. When user touch on the screen and move, a circle will be drawn.
There is a customized MyView class, extends from View. The onTouchEvent(MotionEvent event) method is used to handle the user touch events; such as ACTION_MOVE, ACTION_DOWN and ACTION_UP. Then it calls invalidate() to force the view to be redraw, onDraw(Canvas canvas) will be called in turn.
AndroidViewUI.java
Download the file.
Related Article: Instance two object from the same custom view class
There is a customized MyView class, extends from View. The onTouchEvent(MotionEvent event) method is used to handle the user touch events; such as ACTION_MOVE, ACTION_DOWN and ACTION_UP. Then it calls invalidate() to force the view to be redraw, onDraw(Canvas canvas) will be called in turn.
AndroidViewUI.java
package com.exercise.AndroidViewUI;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class AndroidViewUI extends Activity {
public class MyView extends View {
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private float initX, initY, radius;
private boolean drawing = false;
public MyView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}
public MyView(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);
}
@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
if(drawing){
canvas.drawCircle(initX, initY, radius, paint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
int action = event.getAction();
if (action==MotionEvent.ACTION_MOVE){
float x = event.getX();
float y = event.getY();
radius = (float) Math.sqrt(Math.pow(x-initX, 2) + Math.pow(y-initY, 2));
}
else if (action==MotionEvent.ACTION_DOWN){
initX = event.getX();
initY = event.getY();
radius = 1;
drawing = true;
}
else if (action==MotionEvent.ACTION_UP){
drawing = false;
}
invalidate();
return true;
}
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
MyView myView = new MyView(this);
setContentView(myView);
}
}
Download the file.
Related Article: Instance two object from the same custom view class
Thursday, 20 May 2010
Android 2.2 platform available for the Android SDK
The Android 2.2 platform is now available for the Android SDK, along with new tools, documentation, and a new NDK.
Android 2.2 is a minor platform release including user features, developer features, API changes, and bug fixes. For information on developer features and API changes, see the Framework API section.
For developers, the Android 2.2 platform is available as a downloadable component for the Android SDK. The downloadable platform includes a fully compliant Android library and system image, as well as a set of emulator skins, sample applications, and more. The downloadable platform includes no external libraries.
You can refer to my article to know how to Install Android SDK on Eclipse 3.5 Galileo, in Ubuntu 9.10. Or, if you have install Android 1.6 SDK or later version, you can refer to another article to upgrade Android SDK using Android SDK and AVD Manager.
Android 2.2 is a minor platform release including user features, developer features, API changes, and bug fixes. For information on developer features and API changes, see the Framework API section.
For developers, the Android 2.2 platform is available as a downloadable component for the Android SDK. The downloadable platform includes a fully compliant Android library and system image, as well as a set of emulator skins, sample applications, and more. The downloadable platform includes no external libraries.
You can refer to my article to know how to Install Android SDK on Eclipse 3.5 Galileo, in Ubuntu 9.10. Or, if you have install Android 1.6 SDK or later version, you can refer to another article to upgrade Android SDK using Android SDK and AVD Manager.
Custom JQuery Form Validation Plugin
Check out this custom form validation plugin by AJ Graham. Worth a look.
Network Tethering for the iPhone?
Looks like we may finally get tethering for the iPhone. Probably not for free though, expect extra charges for bandwidth.
Wednesday, 19 May 2010
TinyUmbrella - Unified TinyTSS and The Firmware Umbrella in ONE!
03.13.83 - Changes
03.13.81 - Changes
TinyUmbrella is ready for testing. I've done most of what I said I would do in the last post. TinyUmbrella is a combination SHSH file saver as well as local TSS server. For those of you that have no idea what that is I'll explain.
If you have one of the following devices:
TinyUmbrella sends the same exact request that iTunes sends Apple when requesting the signatures for your device to be restored. The difference is that TinyUmbrella does not need to do anything to your device. You do not need to be on the firmware version that TinyUmbrella is requesting signatures. As an example, I've been on 3.1.2 for quite some time. TinyUmbrella has saved my 3.1, 3.1.2 and 3.1.3 signatures. This is because the request that iTunes sends to Apple includes your ECID and the details about the firmware version. Apple sends the response signatures and TinyUmbrella saves them so you can use them whenever you want; Even if Apple has stopped signing that particular version.
The latest version of TinyUmbrella contains a small server that forces iTunes to connect to it instead of going to the apple servers. When you run TinyUmbrella and start the TSS server, your saved SHSH signatures will be cached up and ready for use. Once TinyUmbrella is running and the TSS server is running. You can open iTunes and start your restore to the firmware version you have SHSH files for. iTunes will accept the responses as if they had come from Apple itself.
It is important to realize that Apple can disable this in a future iTunes update. Currently iTunes v9.1.1 (12) works perfectly. Always be wary of any iTunes updates. Feel free to follow me on twitter (@notcom) and I'll let you know if iTunes versions are TinyUmbrella - safe.
TinyUmbrella is also able to detect your ECID so you don't have to do anything like enter recovery and search through obscure system windows to find your ECID. It's automatic. All you have to do to save your SHSH is press the Save My SHSH button. TinyUmbrella even makes the request through Cydia so that Cydia will have your device's SHSH signatures 'on-file' immediately. This gives you double protection of having your SHSH signatures locally as well as on Saurik's trusted servers.
I put a lot of work on this little tool. I hope it helps many of you restore your devices even after Apple thinks you shouldn't be able to. In my opinion, I should be the final say when it comes to what versions of what software runs on my device. I think you feel the same way too.
I've made the OSX and Windows versions of TinyUmbrella available for beta testing. It's an open beta so feel free to give it a try. Let me know if you come across any issues. Here are the system requirements:
OSX
I plan on fixing bugs before release and getting the Linux version completely working before calling it a release.
- Fixed a bug for ppc users. Sorry minimum osx required version is 10.5 - I couldn't get the thing working in 10.4 because of some dependency changes from 10.4 -> 10.5.
- Should now work on mac mini's if you have Leopard.
- Cosmetic changes
- Some small refactorings to get ready for ios4.
03.13.81 - Changes
- OK so I fixed a huge error that rendered restores basically impossible because of some stupid oversight. Please update to 03.13.81 so you can correctly restore your device and not fail at the iTunes screen :) Thanks guys - keep the bug reports coming!
- I can confirm that restores work as I've used my own iPhone 3GS on 3.1.2 as a test.
- Detects if port 80 is in use and should properly report why it cannot start. I may add a feature to detect the actual PID that is using port 80.
- Added the region info to the model number to aid users in finding the carrier to which their device is locked. IE: Model Numbers in the USA that end in LL/A are locked to AT&T.
- Various and sundry minor defect/exception fixes.
- Added Log instead of a single label for feedback
- Added context menu for ECID text and the Log console
- Copy - Copy the whole ecid to clipboard
- Copy (Hex) - Copy the ecid as Hex number
- Paste - Paste the ECID in the clipboard
- Clear - Duh?
- Pastebin submission of log file (right click -> Pastebin Log)
- Hovering over ECID field will display a tooltip of the ECID in Hex format
- The OSX version no longer needs to be started twice the very first time its launched! (I no longer fail at execl!)
- The OSX version now should work on Leopard (10.5)
- The OSX version can be dragged into the /Applications folder
TinyUmbrella is ready for testing. I've done most of what I said I would do in the last post. TinyUmbrella is a combination SHSH file saver as well as local TSS server. For those of you that have no idea what that is I'll explain.
If you have one of the following devices:
- iPhone 3GS
- iPod Touch 3rd Generation (32 or 64)
- iPod Touch 2nd Generation (with a model number MC)
TinyUmbrella sends the same exact request that iTunes sends Apple when requesting the signatures for your device to be restored. The difference is that TinyUmbrella does not need to do anything to your device. You do not need to be on the firmware version that TinyUmbrella is requesting signatures. As an example, I've been on 3.1.2 for quite some time. TinyUmbrella has saved my 3.1, 3.1.2 and 3.1.3 signatures. This is because the request that iTunes sends to Apple includes your ECID and the details about the firmware version. Apple sends the response signatures and TinyUmbrella saves them so you can use them whenever you want; Even if Apple has stopped signing that particular version.
The latest version of TinyUmbrella contains a small server that forces iTunes to connect to it instead of going to the apple servers. When you run TinyUmbrella and start the TSS server, your saved SHSH signatures will be cached up and ready for use. Once TinyUmbrella is running and the TSS server is running. You can open iTunes and start your restore to the firmware version you have SHSH files for. iTunes will accept the responses as if they had come from Apple itself.
It is important to realize that Apple can disable this in a future iTunes update. Currently iTunes v9.1.1 (12) works perfectly. Always be wary of any iTunes updates. Feel free to follow me on twitter (@notcom) and I'll let you know if iTunes versions are TinyUmbrella - safe.
TinyUmbrella is also able to detect your ECID so you don't have to do anything like enter recovery and search through obscure system windows to find your ECID. It's automatic. All you have to do to save your SHSH is press the Save My SHSH button. TinyUmbrella even makes the request through Cydia so that Cydia will have your device's SHSH signatures 'on-file' immediately. This gives you double protection of having your SHSH signatures locally as well as on Saurik's trusted servers.
I put a lot of work on this little tool. I hope it helps many of you restore your devices even after Apple thinks you shouldn't be able to. In my opinion, I should be the final say when it comes to what versions of what software runs on my device. I think you feel the same way too.
I've made the OSX and Windows versions of TinyUmbrella available for beta testing. It's an open beta so feel free to give it a try. Let me know if you come across any issues. Here are the system requirements:
OSX
- OSX 10.6.x - known issues on 10.5
- Java 1.5+ (ships with 10.6)
- iTunes 9.0 - iTunes 9.1.1 (25) (other versions I'm not 100%)
- Administrator Privileges to run on port 80 and make /etc/hosts modifications
- Windows XP, Vista, 7 (x86 or 64bit)
- Java 32 bit (VERY important - will not work if you have 64 bit Java running)
- iTunes 9.0 - iTunes 9.1.1 (25) (I've personally tested on 9.0.0 and 9.1.1)
- Administrator privileges for running on port 80 and making hosts changes
I plan on fixing bugs before release and getting the Linux version completely working before calling it a release.
Android FaceDetector
Android provide a class android.media.FaceDetector to identify the faces of people in a Bitmap graphic object.
It's a simple exercise of face detection on Android. You have to place your own photo (in 320x480) into /res/drawable folder, or use the attached photos from the download link on the bottom of the text.
Download the files.
Related:
- Face detection for Camera
It's a simple exercise of face detection on Android. You have to place your own photo (in 320x480) into /res/drawable folder, or use the attached photos from the download link on the bottom of the text.
package com.exercise.AndroidFaceDetector;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.media.FaceDetector;
import android.media.FaceDetector.Face;
import android.os.Bundle;
import android.view.View;
public class AndroidFaceDetector extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
setContentView(new myView(this));
}
private class myView extends View{
private int imageWidth, imageHeight;
private int numberOfFace = 5;
private FaceDetector myFaceDetect;
private FaceDetector.Face[] myFace;
float myEyesDistance;
int numberOfFaceDetected;
Bitmap myBitmap;
public myView(Context context) {
super(context);
// TODO Auto-generated constructor stub
BitmapFactory.Options BitmapFactoryOptionsbfo = new BitmapFactory.Options();
BitmapFactoryOptionsbfo.inPreferredConfig = Bitmap.Config.RGB_565;
myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.face5, BitmapFactoryOptionsbfo);
imageWidth = myBitmap.getWidth();
imageHeight = myBitmap.getHeight();
myFace = new FaceDetector.Face[numberOfFace];
myFaceDetect = new FaceDetector(imageWidth, imageHeight, numberOfFace);
numberOfFaceDetected = myFaceDetect.findFaces(myBitmap, myFace);
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
canvas.drawBitmap(myBitmap, 0, 0, null);
Paint myPaint = new Paint();
myPaint.setColor(Color.GREEN);
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setStrokeWidth(3);
for(int i=0; i < numberOfFaceDetected; i++)
{
Face face = myFace[i];
PointF myMidPoint = new PointF();
face.getMidPoint(myMidPoint);
myEyesDistance = face.eyesDistance();
canvas.drawRect(
(int)(myMidPoint.x - myEyesDistance),
(int)(myMidPoint.y - myEyesDistance),
(int)(myMidPoint.x + myEyesDistance),
(int)(myMidPoint.y + myEyesDistance),
myPaint);
}
}
}
}
Download the files.
Related:
- Face detection for Camera
iPad: GoodReader is really good for PDFs
Hey iPad fans out there. I have been looking for a good PDF reader and I have finally found one. Get GoodReader for $1. It reads not only PDFs, but .txt files, Word files, and a number of other formats.
For the iPad, its the best thing out there. It actually creates a Table of Contents for most PDF documents. Which is a requirement for most large documents and is a feature left out of most PDF readers for the iPad. You can size documents with gestures which is nice. My only complaint is you navigate through documents my clicking at the top and bottom of a page which is counter to the prevailing standard of clicking left on right for most other readers on the iPad. When I have time I can hopefully provide a better review. But for now, if you need to read PDFs, get this app!!!!
For the iPad, its the best thing out there. It actually creates a Table of Contents for most PDF documents. Which is a requirement for most large documents and is a feature left out of most PDF readers for the iPad. You can size documents with gestures which is nice. My only complaint is you navigate through documents my clicking at the top and bottom of a page which is counter to the prevailing standard of clicking left on right for most other readers on the iPad. When I have time I can hopefully provide a better review. But for now, if you need to read PDFs, get this app!!!!
JQuery Circular Animation
Want to add a cool animation effect to your site? Check out this circular animation implemented as a JQuery plugin. Pretty cool.
Sunday, 16 May 2010
TinyUmbrella - Coming Soon.
Edit: Thank you @iOPK for the awesome header ;)
Umbrella and TinyTSS are in the process of being merged into a single app. Basically I've added a button to the new Umbrella UI. This button allows you to turn on and off the TinyTSS server. I'm also adding a ton of features to the app as a whole to make it more user friendly. Here are some ideas I'm currently working on / have already implemented locally (on my machine).
I plan on getting this stuff wrapped up over the next week or so. Trust me - it's going to make life so much easier for everyone that has no idea what java -jar tinytss.jar means.
:)
Umbrella and TinyTSS are in the process of being merged into a single app. Basically I've added a button to the new Umbrella UI. This button allows you to turn on and off the TinyTSS server. I'm also adding a ton of features to the app as a whole to make it more user friendly. Here are some ideas I'm currently working on / have already implemented locally (on my machine).
- Auto configuration of the hosts file - no more messing with the hosts - I do it for you (with the backup being named hosts.umbrella) yes for Windows, Mac, and Linux (If you can figure out a way to restore using Linux that is :) ).
- Umbrella now will save your shsh files silently in a new directory (~/.shsh). This allows the built in TSS server to read all of the files in that directory and cache them.
- Umbrella will support drag and drop. My goal will be for you to be able to drag your .shsh files and drop them onto Umbrella and Umbrella will save the files to the ~/.shsh directory. I also plan on supporting the OLD 00.shsh 01.shsh 02.shsh files as well :)
- [OSX ONLY] - Because Umbrella's built in TSS will need to run on port 80, Umbrella will ask you for your superuser password just once (Through the Authorization mechanism - which means your operating system will ask for your permission not me). This will explain the admin popup you will receive when Umbrella runs for the first time on your machine. After this first time, the application will exit and the next time you run Umbrella it will be able to start the service on port 80.
- Already mentioned but this is still a HUGE code change - Umbrella's built in TSS server will cache multiple .shsh files (dragging and dropping shsh files onto Umbrella will add them to the TSS cache immediately). This also means that the TSS server will now intelligently respond to the request based on the ECID in the request instead of stupidly spitting out whatever data is in the .shsh file loaded at startup.
- iPhone3GS 3.1.2 (7D11) - 123412341234
- iPhone3GS 3.1.3 (7E18) - 123412341234
- iPod3G 3.1.3 (7E18) - 222233334444
- iPod2G 3.1.2 (7D11) - 111133332222
I plan on getting this stuff wrapped up over the next week or so. Trust me - it's going to make life so much easier for everyone that has no idea what java -jar tinytss.jar means.
:)
Friday, 14 May 2010
WebTip: Gray Shade Suddenly Covers Half Your Site
Problem: You load your site in Firefox. The upper half of the page is covered by a gray shade and you can't click on anything under it. This problem seems to have randomly appeared.
Solution: This appears to be a bug with Google Analytics and Firefox (3.6.3 for me). If you use the Analytics overlay feature to view a site, then the next time you try to view the site in Firefox, you have this problem. To fix it, simply delete all your cookies. Or if you can find it, only delete the analytics cookies.
Note: If you look at your code in Firebug, you will see Analytics has added this code to your page.
Removing the cookie removes the above HTML code from your page.
Solution: This appears to be a bug with Google Analytics and Firefox (3.6.3 for me). If you use the Analytics overlay feature to view a site, then the next time you try to view the site in Firefox, you have this problem. To fix it, simply delete all your cookies. Or if you can find it, only delete the analytics cookies.
Note: If you look at your code in Firebug, you will see Analytics has added this code to your page.
<div id="ga_shade" style="background-color: #eeeeee; display: block; height: 1000px; left: 0px; opacity: 0.5; position: absolute; top: 0px; width: 100%; z-index: 100000;"></div>
Removing the cookie removes the above HTML code from your page.
Draw something on a Canvas
Simple draw something (drawRect) on a Canvas over a bitmap on a View.
Modify from the previous article "Draw a bitmap on View". In order to draw something, a object of Paint class have to been create, and set some parameter; such as color, style, Strok.
Modify the code:
Download the files.
Next: Android FaceDetector
Next: Custom View with User Interaction
Modify from the previous article "Draw a bitmap on View". In order to draw something, a object of Paint class have to been create, and set some parameter; such as color, style, Strok.
Modify the code:
package com.exercise.AndroidPaint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.View;
public class AndroidPaint extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
setContentView(new myView(this));
}
private class myView extends View{
public myView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.googlelogo320x480);
canvas.drawBitmap(myBitmap, 0, 0, null);
Paint myPaint = new Paint();
myPaint.setColor(Color.GREEN);
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setStrokeWidth(3);
canvas.drawRect(10, 10, 100, 100, myPaint);
}
}
}
Download the files.
Next: Android FaceDetector
Next: Custom View with User Interaction
Thursday, 13 May 2010
So Much for the NetBook Experiment
Well I have been playing around with a 10" HP Netbook for the last 6 months or so. I have taken it on business trips, vacations, and just around town. My goal was to use it as much as possible and see how useful it is.
My conclusion. Netbooks are just too damn small. lol. From a purely technical point of view, there is nothing to complain about. The Intel Atom CPU has plenty of power and Windows 7 is a pretty sweet OS. The HP has a great screen and really good battery life. Surfing the Web on Chrome or Firefox is good. And you can hardly feel it when you carry it around.
But have you ever tried to put the thing in your lap and work on it for more than 15 minutes? Or actually do some writing or coding on the screen? It just doesn't fit or work well. I feel like I have stolen a device from a gnome. lol.
Thus my enthusiasm for the iPad in a previous post. Instead of feeling small, it feels just about right. So its back to my 13" Macbook for actually getting something done and being portable.
Umbrella Released with device detection on OSX, Windows, Linux
Edit: I've re-added the v222 zip for TinyTSS while I work on the rewrite.
I've finished the first round of fixes with Umbrella. Umbrella now supports mac, windows, and linux although linux is a bit flaky until I iron out some (non critical) defects. (I'm aware of the segmentation fault but I haven't pinned it down)
Eventually Umbrella and TinyTSS will be combined into the same application. Now that I've gotten device detection finished on Umbrella I can work on the TinyTSS rewrite.
As always keep me posted if you find any bugs.
Special thanks to @iOPK for the icons!
umbrella.exe md5: 3c762b9b2087b97d17599079d2527667
Umbrella-03.13.32.dmg md5: 2849f10bb0056bb9c1dca66e2d688f06
umbrella-linux-03.13.32.zip: ba176cfd27464f2d38d59378145b82c1
I've finished the first round of fixes with Umbrella. Umbrella now supports mac, windows, and linux although linux is a bit flaky until I iron out some (non critical) defects. (I'm aware of the segmentation fault but I haven't pinned it down)
Eventually Umbrella and TinyTSS will be combined into the same application. Now that I've gotten device detection finished on Umbrella I can work on the TinyTSS rewrite.
As always keep me posted if you find any bugs.
Special thanks to @iOPK for the icons!
umbrella.exe md5: 3c762b9b2087b97d17599079d2527667
Umbrella-03.13.32.dmg md5: 2849f10bb0056bb9c1dca66e2d688f06
umbrella-linux-03.13.32.zip: ba176cfd27464f2d38d59378145b82c1
Wednesday, 12 May 2010
Draw a bitmap on View
It's a simple example to draw a bitmap on screen in View. The content view is set to a View, and the drawing is achieved in onDraw method.
To make it simple, a bitmap of 320x480 (the size of HVGA) was prepared. It's in /res/drawable/ folder, and will be loaded using the following codes:
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.googlelogo320x480);
canvas.drawBitmap(myBitmap, 0, 0, null);
Download the files.
Next: Draw something on a Canvas.
To make it simple, a bitmap of 320x480 (the size of HVGA) was prepared. It's in /res/drawable/ folder, and will be loaded using the following codes:
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.googlelogo320x480);
canvas.drawBitmap(myBitmap, 0, 0, null);
package com.exercise.AndroidPaint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Bundle;
import android.view.View;
public class AndroidPaint extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
setContentView(new myView(this));
}
private class myView extends View{
public myView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.googlelogo320x480);
canvas.drawBitmap(myBitmap, 0, 0, null);
}
}
}
Download the files.
Next: Draw something on a Canvas.
Tuesday, 11 May 2010
Switching to a New Feed
Blogger has a new feed system so I'm switching over to it.
The new feed URL is:
http://feeds.feedburner.com/blogspot/wBnvR
I am guessing the old feed URL will continue to work for a while. Please update your reader. Thanks.
The new feed URL is:
http://feeds.feedburner.com/blogspot/wBnvR
I am guessing the old feed URL will continue to work for a while. Please update your reader. Thanks.
Monday, 10 May 2010
File Manager in iPod/iPad OS?
Check out this post on a file manager being included in the iPod 4 operating system.
This is exciting news, as the iPod, iPhone, and iPad could really use a global file/folder space. Right now, it seems like each application is sort of self contained. It would be nice to be able to share HTML files and the like. It will be interesting to see how this work and how applications will interact with it. If its included in the final version. :)
This is exciting news, as the iPod, iPhone, and iPad could really use a global file/folder space. Right now, it seems like each application is sort of self contained. It would be nice to be able to share HTML files and the like. It will be interesting to see how this work and how applications will interact with it. If its included in the final version. :)
A simple RSS reader III, show details once item clicked.
Last article "A simple RSS reader II, implement with RSSFeed & RSSItem", only the titles shown in a List. Here, we are going to start another activity to show the details once any item in the list clicked.
Most of the works from the last article "A simple RSS reader II, implement with RSSFeed & RSSItem", with the changes lsited below.
Implement /res/layout/details.xml, it's the layout of the activity ShowDetails.java
Implement a new Activity /src/com.exercise.AndroidRssReader/ShowDetails.java, it will be started once any item in the list clicked.
Modify /src/com.exercise.AndroidRssReader/AndroidRssReader.java to start new activity once any list item clicked.
Modify AndroidManifest.xml to include the new activity.
Download the files.
next:
- Apply custom adapter to ListView for RSS Reader
- A simple RSS reader IV, start browser to open the selected feed
Most of the works from the last article "A simple RSS reader II, implement with RSSFeed & RSSItem", with the changes lsited below.
Implement /res/layout/details.xml, it's the layout of the activity ShowDetails.java
<?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="RSS Details:-" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/detailstitle" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/detailsdescription" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:id="@+id/detailslink" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/detailspubdate" />
</LinearLayout>
Implement a new Activity /src/com.exercise.AndroidRssReader/ShowDetails.java, it will be started once any item in the list clicked.
package com.exercise.AndroidRssReader;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class ShowDetails extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.details);
TextView detailsTitle = (TextView)findViewById(R.id.detailstitle);
TextView detailsDescription = (TextView)findViewById(R.id.detailsdescription);
TextView detailsPubdate = (TextView)findViewById(R.id.detailspubdate);
TextView detailsLink = (TextView)findViewById(R.id.detailslink);
Bundle bundle = this.getIntent().getExtras();
detailsTitle.setText(bundle.getString("keyTitle"));
detailsDescription.setText(bundle.getString("keyDescription"));
detailsPubdate.setText(bundle.getString("keyPubdate"));
detailsLink.setText(bundle.getString("keyLink"));
}
}
Modify /src/com.exercise.AndroidRssReader/AndroidRssReader.java to start new activity once any list item clicked.
package com.exercise.AndroidRssReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class AndroidRssReader extends ListActivity {
private RSSFeed myRssFeed = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
URL rssUrl = new URL("http://www.gov.hk/en/about/rss/govhkrss.data.xml");
SAXParserFactory mySAXParserFactory = SAXParserFactory.newInstance();
SAXParser mySAXParser = mySAXParserFactory.newSAXParser();
XMLReader myXMLReader = mySAXParser.getXMLReader();
RSSHandler myRSSHandler = new RSSHandler();
myXMLReader.setContentHandler(myRSSHandler);
InputSource myInputSource = new InputSource(rssUrl.openStream());
myXMLReader.parse(myInputSource);
myRssFeed = myRSSHandler.getFeed();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (myRssFeed!=null)
{
TextView feedTitle = (TextView)findViewById(R.id.feedtitle);
TextView feedDescribtion = (TextView)findViewById(R.id.feeddescribtion);
TextView feedPubdate = (TextView)findViewById(R.id.feedpubdate);
TextView feedLink = (TextView)findViewById(R.id.feedlink);
feedTitle.setText(myRssFeed.getTitle());
feedDescribtion.setText(myRssFeed.getDescription());
feedPubdate.setText(myRssFeed.getPubdate());
feedLink.setText(myRssFeed.getLink());
ArrayAdapter<RSSItem> adapter =
new ArrayAdapter<RSSItem>(this,
android.R.layout.simple_list_item_1,myRssFeed.getList());
setListAdapter(adapter);
}
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
Intent intent = new Intent(this,ShowDetails.class);
Bundle bundle = new Bundle();
bundle.putString("keyTitle", myRssFeed.getItem(position).getTitle());
bundle.putString("keyDescription", myRssFeed.getItem(position).getDescription());
bundle.putString("keyLink", myRssFeed.getItem(position).getLink());
bundle.putString("keyPubdate", myRssFeed.getItem(position).getPubdate());
intent.putExtras(bundle);
startActivity(intent);
}
}
Modify AndroidManifest.xml to include the new activity.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.exercise.AndroidRssReader"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".AndroidRssReader"
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=".ShowDetails"></activity>
</application>
<uses-sdk android:minSdkVersion="4" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
Download the files.
next:
- Apply custom adapter to ListView for RSS Reader
- A simple RSS reader IV, start browser to open the selected feed
Saturday, 8 May 2010
A simple RSS reader II, implement with RSSFeed & RSSItem
In the previous article "A simple RSS reader, in ListView", I just show a very simple RSS reader, with a very limited handling on the RSSHandle events. Here, I will show in more details, also in better orgination.
First of all, the source of the feed is changed to http://www.gov.hk/en/about/rss/govhkrss.data.xml, it's a feed from Hong Kong Government; because the original blogger's feed is too complicated for me to demo here!
Here, RSSHandler, RSSFeed and RSSItems are implemented as separated class for better organization. The application have a single object of RSSFeed class, which consist a list of RSSItem object. More details (Title, PubDate, Description and Link) of the feed and individual items are saved in the structure, which can be retrieved later.
AndroidManifest.xml to grant "android.permission.INTERNET" to the application. (Refer to last article "A simple RSS reader, using Android's org.xml.sax package")
Keep the rsslist.xml as before
Modify main.xml
Implement /src/com.exercise.AndroidRssReader/RSSItem.java
Implement /src/com.exercise.AndroidRssReader/RSSFeed.java
Implemenet /src/com.exercise.AndroidRssReader/RSSHandler.java
Modify /src/com.exercise.AndroidRssReader/AndroidRssReader.java
Download the files.
Next: A simple RSS reader III, show details once item clicked.
First of all, the source of the feed is changed to http://www.gov.hk/en/about/rss/govhkrss.data.xml, it's a feed from Hong Kong Government; because the original blogger's feed is too complicated for me to demo here!
Here, RSSHandler, RSSFeed and RSSItems are implemented as separated class for better organization. The application have a single object of RSSFeed class, which consist a list of RSSItem object. More details (Title, PubDate, Description and Link) of the feed and individual items are saved in the structure, which can be retrieved later.
AndroidManifest.xml to grant "android.permission.INTERNET" to the application. (Refer to last article "A simple RSS reader, using Android's org.xml.sax package")
Keep the rsslist.xml as before
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rowtext"
android:layout_width="fill_parent"
android:layout_height="25px"
android:textSize="10sp" />
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:id="@+id/feedtitle" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/feeddescribtion" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/feedpubdate" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:id="@+id/feedlink" />
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@android:id/empty"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="No Data" />
</LinearLayout>
Implement /src/com.exercise.AndroidRssReader/RSSItem.java
package com.exercise.AndroidRssReader;
public class RSSItem {
private String title = null;
private String description = null;
private String link = null;
private String pubdate = null;
RSSItem(){
}
void setTitle(String value)
{
title = value;
}
void setDescription(String value)
{
description = value;
}
void setLink(String value)
{
link = value;
}
void setPubdate(String value)
{
pubdate = value;
}
String getTitle()
{
return title;
}
String getDescription()
{
return description;
}
String getLink()
{
return link;
}
String getPubdate()
{
return pubdate;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return title;
}
}
Implement /src/com.exercise.AndroidRssReader/RSSFeed.java
package com.exercise.AndroidRssReader;
import java.util.List;
import java.util.Vector;
public class RSSFeed {
private String title = null;
private String description = null;
private String link = null;
private String pubdate = null;
private List<RSSItem> itemList;
RSSFeed(){
itemList = new Vector<RSSItem>(0);
}
void addItem(RSSItem item){
itemList.add(item);
}
RSSItem getItem(int location){
return itemList.get(location);
}
List<RSSItem> getList(){
return itemList;
}
void setTitle(String value)
{
title = value;
}
void setDescription(String value)
{
description = value;
}
void setLink(String value)
{
link = value;
}
void setPubdate(String value)
{
pubdate = value;
}
String getTitle()
{
return title;
}
String getDescription()
{
return description;
}
String getLink()
{
return link;
}
String getPubdate()
{
return pubdate;
}
}
Implemenet /src/com.exercise.AndroidRssReader/RSSHandler.java
package com.exercise.AndroidRssReader;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class RSSHandler extends DefaultHandler {
final int state_unknown = 0;
final int state_title = 1;
final int state_description = 2;
final int state_link = 3;
final int state_pubdate = 4;
int currentState = state_unknown;
RSSFeed feed;
RSSItem item;
boolean itemFound = false;
RSSHandler(){
}
RSSFeed getFeed(){
return feed;
}
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
feed = new RSSFeed();
item = new RSSItem();
}
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
if (localName.equalsIgnoreCase("item")){
itemFound = true;
item = new RSSItem();
currentState = state_unknown;
}
else if (localName.equalsIgnoreCase("title")){
currentState = state_title;
}
else if (localName.equalsIgnoreCase("description")){
currentState = state_description;
}
else if (localName.equalsIgnoreCase("link")){
currentState = state_link;
}
else if (localName.equalsIgnoreCase("pubdate")){
currentState = state_pubdate;
}
else{
currentState = state_unknown;
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// TODO Auto-generated method stub
if (localName.equalsIgnoreCase("item")){
feed.addItem(item);
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// TODO Auto-generated method stub
String strCharacters = new String(ch,start,length);
if (itemFound==true){
// "item" tag found, it's item's parameter
switch(currentState){
case state_title:
item.setTitle(strCharacters);
break;
case state_description:
item.setDescription(strCharacters);
break;
case state_link:
item.setLink(strCharacters);
break;
case state_pubdate:
item.setPubdate(strCharacters);
break;
default:
break;
}
}
else{
// not "item" tag found, it's feed's parameter
switch(currentState){
case state_title:
feed.setTitle(strCharacters);
break;
case state_description:
feed.setDescription(strCharacters);
break;
case state_link:
feed.setLink(strCharacters);
break;
case state_pubdate:
feed.setPubdate(strCharacters);
break;
default:
break;
}
}
currentState = state_unknown;
}
}
Modify /src/com.exercise.AndroidRssReader/AndroidRssReader.java
package com.exercise.AndroidRssReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import android.app.ListActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class AndroidRssReader extends ListActivity {
private RSSFeed myRssFeed = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
URL rssUrl = new URL("http://www.gov.hk/en/about/rss/govhkrss.data.xml");
SAXParserFactory mySAXParserFactory = SAXParserFactory.newInstance();
SAXParser mySAXParser = mySAXParserFactory.newSAXParser();
XMLReader myXMLReader = mySAXParser.getXMLReader();
RSSHandler myRSSHandler = new RSSHandler();
myXMLReader.setContentHandler(myRSSHandler);
InputSource myInputSource = new InputSource(rssUrl.openStream());
myXMLReader.parse(myInputSource);
myRssFeed = myRSSHandler.getFeed();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (myRssFeed!=null)
{
TextView feedTitle = (TextView)findViewById(R.id.feedtitle);
TextView feedDescribtion = (TextView)findViewById(R.id.feeddescribtion);
TextView feedPubdate = (TextView)findViewById(R.id.feedpubdate);
TextView feedLink = (TextView)findViewById(R.id.feedlink);
feedTitle.setText(myRssFeed.getTitle());
feedDescribtion.setText(myRssFeed.getDescription());
feedPubdate.setText(myRssFeed.getPubdate());
feedLink.setText(myRssFeed.getLink());
ArrayAdapter<RSSItem> adapter =
new ArrayAdapter<RSSItem>(this,
android.R.layout.simple_list_item_1,myRssFeed.getList());
setListAdapter(adapter);
}
}
}
Download the files.
Next: A simple RSS reader III, show details once item clicked.
Subscribe to:
Posts (Atom)