このエントリーをはてなブックマークに追加

2010年5月24日月曜日

Android TextView with Image



[In English]
I sometimes have the case to arrange the image next to the characters.
We can do it by putting TextView and ImageView into Layout.
But today I introduce the other way using only TextView.
The following sample code is how to show the image next to text.
(show four image(left, top, right, bottom of text))

final TextView textView = (TextView)findViewById(R.id.diet_log_label);
final Drawable iconDrawable = getResources().getDrawable(R.drawable.icon);
textView.setCompoundDrawablesWithIntrinsicBounds(iconDrawable, iconDrawable, iconDrawable, iconDrawable);
// or
textView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.icon, R.drawable.icon, R.drawable.icon, R.drawable.icon);

To show only left image, write "setCompoundDrawablesWithIntrinsicBounds(iconDrawable, null, null, null)".



[In Japanese]
時々文字の隣に画像を配置したい場合があります。
そんな時は、TextViewとImageViewをLayout内に配置することで実現することもできますが、今日はTextViewだけを使った別の方法を紹介したいと思います。
以下は、テキストの上下左右にアイコン画像を表示させるサンプルコードになります。


final TextView textView = (TextView)findViewById(R.id.diet_log_label);
final Drawable iconDrawable = getResources().getDrawable(R.drawable.icon);
textView.setCompoundDrawablesWithIntrinsicBounds(iconDrawable, iconDrawable, iconDrawable, iconDrawable);
// or
textView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.icon, R.drawable.icon, R.drawable.icon, R.drawable.icon);

テキストの左だけ画像を表示させる場合は、setCompoundDrawablesWithIntrinsicBounds(iconDrawable, null, null, null)とします。

2010年5月7日金曜日

How to PopupWindow

[In English]
Today, I'll show you how to use PopupWindow.
PopupWindow enables you to display view on top of the current activity. Actually Dialog class provides similar function, but those are slightly different.
The most distinctive difference is that PopupWindow has function that displays view at anywhere you want though Dialog can not.



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

LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View popupView = (View)inflater.inflate(R.layout.popupwindow_layout, null);
popupView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));

final View view = findViewById(R.id.layout_view);
final PopupWindow popupWindow = new PopupWindow(view);

popupWindow.setContentView(popupView);
popupWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
popupWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);

Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
IBinder windowToken = view.getWindowToken();
if (windowToken != null && windowToken.isBinderAlive()) {
popupWindow.showAtLocation(view, Gravity.BOTTOM | Gravity.CENTER, 10, 10);
}
}
}, 1000);

}





[In Japanese]

今回はPopupWindowの使用方法について記述します。
まずPopupWindowとは、現在表示されているActivityに対し、一番上のレイヤに表示させる事ができるWindowです。Dialogでも同じような動きをしますが、Dialogとの一番の違いは、表示する位置を指定する事ができる点です。Dialogでは基本、show()メソッドを呼び出すだけで、位置の指定まではできません。
では、PopupWindowの基本的な使い方を紹介します。



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

LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View popupView = (View)inflater.inflate(R.layout.popupwindow_layout, null);
popupView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));

final View view = findViewById(R.id.layout_view);
final PopupWindow popupWindow = new PopupWindow(view);

popupWindow.setContentView(popupView);
popupWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
popupWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);

Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
IBinder windowToken = view.getWindowToken();
if (windowToken != null && windowToken.isBinderAlive()) {
popupWindow.showAtLocation(view, Gravity.BOTTOM | Gravity.CENTER, 10, 10);
}
}
}, 1000);

}

2010年4月25日日曜日

Android Intent to Take a Picture

[In English]
When we develop an application, sometimes we use camera function for it.
Of course we can implement our own camera function to our application using camera API, but most of Android Phone provide Camera application.
so today I'll show how to start up camera application and retrieve picture data from it using Intent.


final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, REQUEST_CAMERA);


We need to call Activity using startActivityForResult (not startActivity) to retrieve picture data.


protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CAMERA && resultCode == RESULT_OK) {
// get the picture
final Bitmap bitmap = (Bitmap) data.getExtras().get("data");
// do something for bitmap data
final String sUri = MediaStore.Images.Media.insertImage(
getContentResolver(), bitmap, timestamp, timestamp);



}
}


After taking a picture using Camera application, onActivityResult will be called. And then we can get picture data as Bitmap from extras.
But I feel the quality of bitmap data is not good in this case, because data size in intent extras is limited.



[In Japanese]
アプリケーションを作るときに、場合によってはカメラ機能を使うときもあると思います。
その際に、もちろんカメラAPIを使って独自にカメラ機能を実装することもできますが、ほとんどのAndroid携帯はカメラアプリを提供しています。
そこで、今日はIntentを使ってカメラアプリを起動させ、撮影した写真データを取得する方法を紹介します。


final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, REQUEST_CAMERA);


この場合、写真データを取得するために、startActivityではなく、startActivityForResultを使う必要があります。


protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CAMERA && resultCode == RESULT_OK) {
// get the picture
final Bitmap bitmap = (Bitmap) data.getExtras().get("data");
// do something for bitmap data
final String sUri = MediaStore.Images.Media.insertImage(
getContentResolver(), bitmap, timestamp, timestamp);



}
}


カメラアプリで写真を撮った後、onActivityResultが呼び出されます。そこで、写真データをBitmapとしてextrasから取得できます。
ただ、このBitmapのクオリティはあまりよくないように感じました、おそらくはIntentで渡せるデータサイズに制限があるためだと思います。

2010年4月19日月曜日

how to make kind of Twitter edit box

[In English]
Today, I'm going to make a component something like twitter edit box.
You know, edit box in http://twitter.com indicates the number of words that you can enter in real time.
EditText in Android SDK is not supported this function directory, so we need to implement similar function for ourselves.
We tend to think we can make it by applying a OnKeyListener to EditText.
But we can't in that way.

Basically OnKeyListener will inform you of hardware-keyboard events. But even in software-keyboard, OnKeyListener lets you know typical key events such as 'enter' or 'del'. But you cannot acquire whole events in software-keyborad.

In order to solve this problem, we create a new class extending EditText and then override onTextChanged method.
The method of 'onTextChanged' is called every time edit text is changed. Whichever software-keyboard or hardware-keyboard, you don't have to worry.

That way is very convenient solution this time. I wonder why onTextChanged method is provided as a listener. I think it's more useful for many occasions.

By the way, sample code is like this.


public class WordCountEditText extends EditText {

private TextView wordCountView;

private final static int MAX_LENGTH = 140;

public WordCountEditText(final Context context) {
super(context);
}

public WordCountEditText(final Context context, final AttributeSet attrs) {
super(context, attrs);
}

public WordCountEditText(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}

@Override
protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) {
if (wordCountView != null) {
final int textColor;
int leftLength = MAX_LENGTH - text.length();
if (leftLength < 0) {
textColor = Color.RED;
} else {
textColor = Color.GRAY;
}
wordCountView.setTextColor(textColor);
wordCountView.setText(String.valueOf(leftLength));
}
}

public void setWordCountView(final TextView wordCountView) {
this.wordCountView = wordCountView;
setText(getText());
}
}


And sample code in using class above.


WordCountEditText wordCountEditText = (WordCountEditText)findViewById(R.id.edit_text);
TextView wordCountView = (TextView)findViewById(R.id.word_count_view);
wordCountEditText.setWordCountView(wordCountView);






[In Japanese]
今日は、Twitter風のエディットテキストを作成する方法をご紹介します。
ご存知の通り、http://twitter.com で提供されているエディットボックスは、入力可能な残りの文字数がリアルタイムで表示されます。
残念ながら、Android SDKで提供されているEditTextには、この機能はありません。なので自分達で似たような機能を実装する必要があります。
Android SDKに慣れている人の中には、EditTextにOnKeyListenerを登録する事で実現できると考える人も多いと思います。しかしこのOnKeyListenerは、主にハードウェアキーボードのイベントを通知する為のものです。
ソフトウェアキーボードでも、「確定」キーや「DEL」キーのような代表的なキーのイベントはOnKeyListenerでイベントの検知が可能ですが、全てのイベントを検知する事はできません。

この問題を解決する為には、EditTextを継承した新しいクラスを作成し、onTextChangedメソッドをオーバーライドします。
onTextChangedメソッドは、EditTextの内容が書き換わる度に必ず呼び出されます。ハードウェアキーボードによる変更かソフトウェアキーボーかを気にする必要がありません。

今回の問題を解決するには正にうってつけの方法です。予断ですが、なぜonTextChangedメソッド相当のListenerが提供されていないのかが不思議です。Listenerが提供されていれば、新しいクラスを作成する必要もありませんし、色々な場面で便利だと思うのですが。

とりあえず、サンプルソースは以下のようになります。


public class WordCountEditText extends EditText {

private TextView wordCountView;

private final static int MAX_LENGTH = 140;

public WordCountEditText(final Context context) {
super(context);
}

public WordCountEditText(final Context context, final AttributeSet attrs) {
super(context, attrs);
}

public WordCountEditText(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}

@Override
protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) {
if (wordCountView != null) {
final int textColor;
int leftLength = MAX_LENGTH - text.length();
if (leftLength < 0) {
textColor = Color.RED;
} else {
textColor = Color.GRAY;
}
wordCountView.setTextColor(textColor);
wordCountView.setText(String.valueOf(leftLength));
}
}

public void setWordCountView(final TextView wordCountView) {
this.wordCountView = wordCountView;
setText(getText());
}
}


で、上記のクラスを使う側のコードが以下です。


WordCountEditText wordCountEditText = (WordCountEditText)findViewById(R.id.edit_text);
TextView wordCountView = (TextView)findViewById(R.id.word_count_view);
wordCountEditText.setWordCountView(wordCountView);

2010年4月8日木曜日

Android Intent to show Location Settings View

[In English]
LocationManager is used in Android to get device location and show the address.
But if location setting is disabled on the device settings, Provider will be NULL.


final LocationManager locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
final Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
final LocationManager locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
final String provider = mLocationManager.getBestProvider(criteria, true);


In the case of the above sample, it is okay only to notify the user with Dialog, but I think it is better to move to Location Settings View because our applications can call the other applications using Intent on Android.


final Intent i = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(i);


Like this if you use Intent, you will not need to implement all function you want to your applications.
I'll continue to write blogs about Intent of Camera, Gallery and so on.



[In Japanese]
Androidアプリで位置情報を取得して、住所などを表示させる場合には、LocationManagerを使用します。
ただ、端末の設定で位置情報の送信を許可していないとProviderとして、nullが返されます。


final LocationManager locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
final Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
final LocationManager locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
final String provider = mLocationManager.getBestProvider(criteria, true);


nullが返された場合に、Dialogなどでユーザに通知するだけでもよいのですが、せっかくAndroidではIntentをつかって、他のアプリを呼び出せるので位置情報の設定画面へ遷移する方がよいと思います。


final Intent i = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(i);


このようにIntentを利用することで、他のアプリを呼び出せ、自分のアプリで全て実装する必要がなくなります。
今後もカメラやギャラリーなどの連携についてブログで紹介したいと思います。

2010年3月30日火曜日

All of three major mobile Carrier will release Android Phone in Japan

[in English]
Actually last year only one carrier Docomo has released Androd Phone in Japan, and few Japanese people except Developers know Android.

But in this year this situation will change greatly, because all of three Japanese major carrier will release Android Phone in this year.

NTT Docomo will release Xperia of Sony Ericson, KDDI release Sharp IS01 and the SoftBank will release HTC Desire.
(And Docomo and KDDI will release Android Market for Japanese Users, too.)


Application Security is very important, so sometimes Carrier check is necessary like iPhone Market of Apple.
But I hope that three Japanese carrier will continue Android Open idea, and also hope personal developers can release their applications with easy procedure to Japanese Carrier Market, too.

Anyway, I am bubbling with this Japanese Change.
And I already have two applications, and will release new one in this April.

I will be watching Japanese Android situation as user and also developer.



[in Japaese]
昨年は、日本ではドコモのみがAndroid携帯をリリースして、開発者を除くとほとんど、Androidは認知されていませんでした。
でも、今年はこの状況が大きく変わりそうです。というのも、日本の3大キャリア全てがAndroid携帯をリリースするからです。

ドコモからはソニーエリクソンのXperiaが、KDDIからはシャープののIS01、そしてソフトバンクからはHTC Desireがリリースされます。
(ドコモとKDDIに関しては、マーケットまで公開する予定のようです。)


アプリケーションのセキュリティ対策は大切だと思います、そのためAppleのiPhoneマーケットのようにキャリアチェックが必要な時もあると思います。
ただ、日本の3キャリアがAndroidのオープン思想は継続してほしいと思っています、また個人の開発者が簡単な手続きだけでキャリアのマーケットへも公開できるようにしてほしいと願っています。

いずれにしても、この日本のAndroidの状況変化にわくわくしています。
私は、既に2つのアプリケーションをリリースしていて、この春に新しいアプリをリリース予定です。

今後も日本のAndroidの市場状況をユーザとして、また開発者としてウォッチしていきたいと思います。

2010年3月22日月曜日

Emoji

[In English]
Do you know emoji?
Emoji is very popular in Japan especially among young women.
It's mainly used in e-mails in order to supplement emotion or decorate e-mails.

Now this time, I'm going to introduce the way to use emoji in android devices.
As a prerequisite to use emoji, the devices need to support emoji.
The android devices that are sold in Japan have the prerequisite, but the Android Emulator or Dev Phone does not.

And all you need to do is add the code below.

EditText editText = (EditText)findViewById(R.id.edit);
Bundle bundle = editText.getInputExtras(true);
if (bundle != null) {
bundle.putBoolean("allowEmoji", true);
}


That's it.

If you use EditText in your application, EditText would come in handy for Japanese by adding the code above. So let's give it a try.



[In Japanese]
絵文字という単語を知ってますか?
絵文字は感情を補完したり、メールを華やかにする為に用いられ、若い女性を中心に日本ではとても人気があります。

今回は、Android端末で絵文字を使用する方法をご紹介します。
まず前提条件として、その端末が絵文字をサポートしている必要があります。日本で販売されているAndroid端末ではサポートされていますが、開発者が使用するAndroidエミュレーターやDev Phoneなどではサポートされていません。

実装的には以下のコードを追加するだけです。

EditText editText = (EditText)findViewById(R.id.edit);
Bundle bundle = editText.getInputExtras(true);
if (bundle != null) {
bundle.putBoolean("allowEmoji", true);
}


アプリケーション内でEditTextを使用する場合は、上記のコードを追加するだけで、日本人にとっては非常に使い勝手が良くなります。ぜひ試してみて下さい。

2010年3月15日月曜日

How to set max length of EditText on source code

[In English]
As you know, we can set max length of EditText on layout xml file,
but in some case I want to set it on source code.

So I looked for setMaxLength method of EditText class,
but this class does not have such kind of method.
Instead of it, it has setFilters method.
The following sample code is how to set max length of EditText.


EditText editText = new EditText(this);
int maxLength = 3;
InputFilter[] FilterArray = new InputFilter[1];
FilterArray[0] = new InputFilter.LengthFilter(maxLength);
editText.setFilters(FilterArray);




[In Japanese]
皆さんご存知のように、EditTextの最大文字数はレイアウトxmlで指定できます。
ただ、いくつかのケースにおいては、ソースコード上で最大文字数を指定したい場合があります。

そこで、EditTextクラスの"setMaxLength"メソッドを探したのですが、EditTextクラスにはそのようなメソッドはないことが分かりました。
そのようなメソッドの代わりに、setFiltersメソッドを利用して最大文字数を指定するようです。
以下にそのサンプルコードを記載します。


EditText editText = new EditText(this);
int maxLength = 3;
InputFilter[] FilterArray = new InputFilter[1];
FilterArray[0] = new InputFilter.LengthFilter(maxLength);
editText.setFilters(FilterArray);

2010年3月1日月曜日

Run Android Market App From Your App

[In English]
Today I wrote how to show the application download view on Android Market from the other application.

It's simple to do it.
Just issue Intent to run Android Market Application with the application package parameter.
The following sample is how to show "CounTap" Aplication on Android Market.


//Uri uri = Uri.parse("market://search?q=pname:jp.linkyou.android.countap");
Uri uri = Uri.parse("market://details?id=jp.linkyou.android.countap");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

This way is useful to stimulate the users to download the paid edition from free edition or dependent applications from the other one.



[In Japanese]
今回は、あるアプリからAndroidマーケット上の別のアプリのダウンロード画面を表示させる方法について、記載します。

実現方法は、すごくシンプルです。
該当のアプリのパッケージパラメータを付与させ、Android Marketアプリを起動させるためのIntentを発行させるだけです。
下記のサンプルは、Androidマーケット上に"CounTap"アプリを表示させる方法になります。


//Uri uri = Uri.parse("market://search?q=pname:jp.linkyou.android.countap");
Uri uri = Uri.parse("market://details?id=jp.linkyou.android.countap");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

上記の方法は、無償版のアプリから有償版のアプリへの導線や依存関係にあるアプリへの導線などに使えると思います。

2010年2月24日水曜日

XLIFF enables you to replacement characters(2)

[In English]
Previously on my last blog.


<string name="remaining_time_message">Only %d minutes left.</string>

String.format(getResources().getString(R.string.remaining_time_message, 10);



In most cases this code works well except in case of singular.

When minute value is singular, the message 'only 1 minutes left.' will be created.
It's wrong message to be accurate. We hope the message 'only 1 minute left.'

For the solution of this problem, we can write like this way.




<string name="remaining_time_message_one">Only 1 minute left.</string>
<string name="remaining_time_message_other">Only %d minutes left.</string>


if (value == 1) {
String.format(getResources().getString(R.string.remaining_time_message_one);
} else {
String.format(getResources().getString(R.string.remaining_time_message_other, value);
}


This code may work well. But there is something wrong with this solution because for example in our language Japanese, there is no differences between in the singular and in the plural.
Japanese doesn't perceive singular as special.
Therefore more properly you need to write this way.


if (Locale.getDefault() == Locale.US || Locale.getDefault() == ...) {
if (value == 1) {
String.format(getResources().getString(R.string.remaining_time_message_one);
} else {
String.format(getResources().getString(R.string.remaining_time_message_other, value);
}
} else {
String.format(getResources().getString(R.string.remaining_time_message_other, value);
}


At last the code works correctly!
But the code above is against total multilingualization because java code is aware of various of languages.

It seems to be difficult to solve it, but with xliff we can write very easy code.

[values] - strings.xml

<plurals name="remaining_time_message">
<item quantity="one">Only 1 minute left.</item>
<item quantity="other">Only <xliff:g id="minutes">%d</xliff:g> minutes left.</item>
</plurals<


[values-ja] - strings.xml

<plurals name="remaining_time_message">
<item quantity="other">残り <xliff:g id="minutes">%d</xliff:g>分</item>
</plurals>



String quantityString = getResources().getQuantityString(R.plurals.remaining_time_message, 10);
String.format(quantityString, minuteValue);


Do you know the merit of this way?
In this way, you don't have to be aware of any languages in Java code.
If you make your program accommodate different languages forward, you don't have to edit Java code at all but just pass translator the xml file and ask for translation. That's all. It's very useful, isn't it?




[In Japanese]

前回のブログの続きです。


<string name="remaining_time_message">Only %d minutes left.</string>

String.format(getResources().getString(R.string.remaining_time_message, 10);


上記のコードはほとんどの場合で正常に動作します。例外は単数形の場合です。
分の数値が1の場合、'only 1 minutes left.'というメッセージが生成される事になります。
これは厳密には間違いで、正しくは'only 1 minute left.'です。

この問題の対処として、次のようなコードを書いたとします。



<string name="remaining_time_message_one">Only 1 minute left.</string>
<string name="remaining_time_message_other">Only %d minutes left.</string>


if (value == 1) {
String.format(getResources().getString(R.string.remaining_time_message_one);
} else {
String.format(getResources().getString(R.string.remaining_time_message_other, value);
}


これも正常に動くように見えます。が、少しだけ問題があります。我々の言語である日本語の場合だと、
単数形の場合と複数形の場合で違うフォーマットのメッセージになるという事はあまりありません。
日本語では単数形を特別扱いしないのです。
なので、より正確には次のようなコードを書く必要があります。


if (Locale.getDefault() == Locale.US || Locale.getDefault() == ...) {
if (value == 1) {
String.format(getResources().getString(R.string.remaining_time_message_one);
} else {
String.format(getResources().getString(R.string.remaining_time_message_other, value);
}
} else {
String.format(getResources().getString(R.string.remaining_time_message_other, value);
}


これで正しく動くプログラムが完成しました。
しかし、残念ながらこれは完全な多言語化対応のプログラムとは言えません。なぜなら、Javaのソースの中で言語を意識してしまっているからです。
この種の問題に完全に対処するのは難しいと感じるかもしれませんが、XLIFFを使用すると簡単に解決できます。


[values] - strings.xml

<plurals name="remaining_time_message">
<item quantity="one">Only 1 minute left.</item>
<item quantity="other">Only <xliff:g id="minutes">%d</xliff:g> minutes left.</item>
</plurals<


[values-ja] - strings.xml

<plurals name="remaining_time_message">
<item quantity="other">残り <xliff:g id="minutes">%d</xliff:g>分</item>
</plurals>



String quantityString = getResources().getQuantityString(R.plurals.remaining_time_message, 10);
String.format(quantityString, minuteValue);


今までとの違いが分かるでしょうか?
このやり方だと、Javaのソース上で言語を意識している箇所を排除できます。
つまり、今後色んな言語に対応させる事になった場合でもJavaのソースは修正しなくてよく、翻訳家の方にxmlファイルを渡して翻訳を依頼すればいいだけになります。
すごい恩恵だと思いませんか?

2010年2月21日日曜日

XLIFF enables you to replacement characters(1)

[In English]
Do you know XLIFF?

The purpose of XLIFF is to make localization process easier.
XLIFF can be used in XML.

The rudimentary way to use is as follows.

At first, we need to declare to use xliff.


<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">


And second, use xliff like this.

<string name="remaining_time_message">Only <xliff:g id="minutes">%d</xliff:g> minutes left.</string>


At the end replace it.

getResources().getString(R.string.remaining_time_message, 10);


Like this way we can create the dynamic message from xml.
But wait a minute. Yes I know how you feel. You might feel that there is easier way than that.

1.

<string name="remaining_time_message">Only %d minutes left.</string>


2.

String.format(getResources().getString(R.string.remaining_time_message, 10);


Yes, the result of the both of them is exactly the same.

The former has a number of advantages. But I'll answer it later.
So much for today.



[In Japanese]

XLIFFをご存知ですか?
XLIFFとはローカライズ作業を簡略化してくれる仕組みで、XML中で使用する事ができます。

基本的な使い方は以下の通りです。

まず始めに、XLIFFを使用するという事を宣言します。

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">



次に、XML中でXLIFFを使用した記述をします。

<string name="remaining_time_message">Only <xliff:g id="minutes">%d</xliff:g> minutes left.</string>



最後に、XML中のXLIFFで記述された部分を置換します。

getResources().getString(R.string.remaining_time_message, 10);



このようにして動的なメッセージを生成する事ができます。
しかし、もっと簡単な方法があると感じた方もいらっしゃるのではないでしょうか。
そうです、XLIFFを使わずとも、以下のようにするともっと簡単に実現できます。
1.

<string name="remaining_time_message">Only %d minutes left.</string>


2.

String.format(getResources().getString(R.string.remaining_time_message, 10);


両者の違いはなんでしょうか?実はXLIFFを用いた方がメリットが大きいんです。
そのメリットは次回に書くことにします。
お楽しみに。

2010年2月14日日曜日

CursorAdapter requires a column named "_id"

[In English]
When I used SimpleCursorAdapter to display some data on ListView, I had an Exception.


private SQLiteDatabase mDb;
private SimpleCursorAdapter mAdapter;
private ListView mListView;

....
....
Cursor c = mDb.rawQuery(SELECT_SOME_MEMBERS_SQL, null);
startManagingCursor(c);
String[] from = new String[] {MEMBER_NAME, MEMBER_AGE, NOTE};
int[] to = new int[]{R.id.TextView_name, R.id.TextView_age, R.id.TextView_note};
mAdapter = new SimpleCursorAdapter(this, R.layout.members_layout, c, from, to);
mListView.setAdapter(mAdapter);
....
....

The above sample code seems fine. But if "SELECT_SOME_MEMBERS_SQL" does not have "_id" column,
this sample cause IllegalArgumentException.
So if you use Database(SQLite) in Android Applications, it is better to add a column named "_id" to all tables to use CursorAdapter.
Or you need to write sql state "select member_id as _id from member_talbe where ....." to get Cursor.

You also can find this matter at Android Developer Site
"Adapter that exposes data from a Cursor to a ListView widget. The Cursor must include a column named "_id" or this class will not work."



[In Japanese]
SimplerCursorAdapterを使って、ListView上にデータを表示させる際に、例外に遭遇しました。


private SQLiteDatabase mDb;
private SimpleCursorAdapter mAdapter;
private ListView mListView;
....
....
....
Cursor c = mDb.rawQuery(SELECT_SOME_MEMBERS_SQL, null);
startManagingCursor(c);
String[] from = new String[] {MEMBER_NAME, MEMBER_AGE, NOTE};
int[] to = new int[]{R.id.TextView_name, R.id.TextView_age, R.id.TextView_note};
mAdapter = new SimpleCursorAdapter(this, R.layout.members_layout, c, from, to);
mListView.setAdapter(mAdapter);
....
....

上記のサンプルコードは一見正常に動くように見ますが、"SELECT_SOME_MEMBERS_SQL"に"_id"カラムがないとIllegalArgumentExceptionが発生します。
そのため、データベース(SQLite)を使用したAndroidアプリケーションをつくる場合には、全てのテーブルに"_id"カラムを加えておくとよいと思います。
もしくは、"select member_id as _id from member_talbe where ....."のようなSQL文でCursorを取得する必要があります。

Android Developerサイトに本件に関する注意の記載があります。
"Adapter that exposes data from a Cursor to a ListView widget. The Cursor must include a column named "_id" or this class will not work."

2010年2月4日木曜日

Android Emulator key mappings

[In English]
On Android Development, Emulator is necessary to check the display of various size.
So today I wanna write some mappings between the emulator keys and and the keys of PC keyboard that is used many times on emulator development

  • Home : Home

  • Menu : F2 or Page up

  • Back : ESC

  • Call : F3

  • End call : F4

  • Switch Orientation : Ctrl-F11


I think that the the mapping keys(Ctrl-F11) worth remembering because it is necessary to switch the orientation of emulator device.
For all mappings between them, please see the developer site.



[In Japanese]
Androidの開発において、様々な画面サイズでの表示確認をするためにエミュレータの使用が欠かせません。
そこで今回は、エミュレータを使用する上で、使用頻度の高いエミュレータキーとPCキーのマッピングをを紹介したいと思います。

  • Home : Home

  • Menu : F2 or Page up

  • Back : ESC

  • Call : F3

  • End call : F4

  • Switch Orientation : Ctrl-F11


端末の向き(landscape/portrait)の変更は、PCキー(Ctrl-F11)を使う必要があるのでぜひ
覚えておきたい操作だと思います。
全てのキーマッピングについては、デベロッパサイトをご参照下さい。

2010年2月2日火曜日

Vibration and BEEP Tone on Android

[In English]
Today's Blog Theme is about Android Vibration and BEEP Tone function.
I feel the application become a little rich only if Vibration and BEEP Tone are added to it.

At first about Vibration function.

Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(1000);


uses-permission is also needed to add to AndroidManifest to use Vibration function.

<uses-permission android:name="android.permission.VIBRATE"/>


Next about BEEP Tone.

ToneGenerator toneGenerator = new ToneGenerator(AudioManager.STREAM_SYSTEM, ToneGenerator.MAX_VOLUME);
toneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP);


At last、the following sample code is about the button effect using combination Vibration and BEEP Tone.

public class HogeActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Vibrator vibrator =
(Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
ToneGenerator toneGenerator =
new ToneGenerator(
AudioManager.STREAM_SYSTEM, ToneGenerator.MAX_VOLUME);
Button button = (Button)findViewById(R.id.button01);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(final View view) {
vibrator.vibrate(1000);
toneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP);
}
});
}
}




[In Japanese]
今回は、バイブレーション機能の使用方法とBEEPトーンを鳴らす方法を紹介したいと思います。
バイブレーションとBEEPトーンを加えるだけで、アプリが少しですがリッチになった気分に
なれます。

先ずは、バイブレーション機能から紹介します。

Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(1000);


バイブレーション機能を使う場合は、AndroidManifest.xmlにuses-permissionにも追加する必要があります。

<uses-permission android:name="android.permission.VIBRATE"/>


次は、BEEPトーンを鳴らす方法です。

ToneGenerator toneGenerator = new ToneGenerator(AudioManager.STREAM_SYSTEM, ToneGenerator.MAX_VOLUME);
toneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP);


最後に、ボタン押下時にバイブレーションとBEEPトーンの組み合わせで、
効果を出すサンプルを記載します。

public class HogeActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Vibrator vibrator =
(Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
ToneGenerator toneGenerator =
new ToneGenerator(
AudioManager.STREAM_SYSTEM, ToneGenerator.MAX_VOLUME);
Button button = (Button)findViewById(R.id.button01);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(final View view) {
vibrator.vibrate(1000);
toneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP);
}
});
}
}

2010年1月31日日曜日

Update Dev Phone to Android 1.6

[In English]
I updated Android Dev phone which is gotten at "Google Developer Day 2009" from Android 1.5 to 1.6.

I'll write the some simple steps to do it, for detail steps please see HTC Web Site

  1. At First, set up the Android SDK to transfer some files to the device.(also need to set the path environment to use adb command)


  2. Download the fastboot from HTC Web Site.


  3. and also download "ota-radio-2_22_19_26I.zip" and "signed-google_ion-img-14721.zip" from HTC Web Site.


  4. Connect the Dev Phone to the PC, and then confirm it with adb command.


  5. C:\Users\Developer\Downloads>adb devices
    List of devices attached
    HT963LF00837 device


  6. Transfer the radio image file to the Dev Phone.


  7. C:\Users\Developer\Downloads>adb push ota-radio-2_22_19_26I.zip /sdcard/update.zip
    C:\Users\Developer\Downloads>adb shell sync


  8. Reboot the Dev Phone.While the Dev Phone is booting, Press the HOME key and the you can see the "!" icon.


  9. At the above view, Press the HOME and END key combination to display the recovery menue, and the select"apply sdcard:update.zip".


  10. After that the Dev phone will reboot, so while it is booting, press BACK key to display the FASTBOOT.


  11. Clear the cache


  12. C:\Users\Developer\Downloads>fastboot erase cache


  13. Flash the image


  14. C:\Users\Developer\Downloads>fastboot update signed-google_ion-img-14721.zip


  15. And then after rebooting, confirm the Firmware Version.("Settings" > "About Phone" > "Firmware version".



At the end, after updating the firmware I can not select Japanese locale
Now I'm continuing to search how to use Japanese locale on Android 1.6 Dev Phone.



[In Japanese]
"Google Developer Day 2009"で頂いたDev PhoneをAndroid 1.5からAndroid 1.6へアップデートしました。

詳細はHTCのサイトを参照するとよくわかると思いますが、簡単なステップだけでもご紹介します。

  1. 先ずは、端末に対してファイル転送などをする必要があるため、SDKをセットアップします。(adbコマンドを使うので環境変数PATHの指定もお忘れなく)


  2. HTCサイトより、アップデートのためのfastbootというツールをダウンロードします。


  3. 同じくHTCサイトより、ota-radio-2_22_19_26I.zipとsigned-google_ion-img-14721.zipをダウンロードします。


  4. Dev PhoneをUSB接続し、認識していることを確認します。


  5. C:\Users\Developer\Downloads>adb devices
    List of devices attached
    HT963LF00837 device


  6. Dev Phoneにradioイメージを転送します。


  7. C:\Users\Developer\Downloads>adb push ota-radio-2_22_19_26I.zip /sdcard/update.zip
    C:\Users\Developer\Downloads>adb shell sync


  8. Dev Phoneの電源を切り、再度起動します。
      起動の時に、HOMEボタン(家のマーク)を押し続けると、「!」アイコンのある画面が表示されます。


  9. 上記の画面で、HOMEボタンと終話ボタンを押し、メニューを表示させ、「apply sdcard:update.zip」をトラックボールを使い選択します。


  10. 再度再起動しますので、起動時に、今度はBACKキーを押し続けると、FASTBOOT画面になります。


  11. キャッシュをクリアします。


  12. C:\Users\Developer\Downloads>fastboot erase cache


  13. イメージを書き込みます。


  14. C:\Users\Developer\Downloads>fastboot update signed-google_ion-img-14721.zip


  15. 再起動されるので、起動後に「Settings」>「About Phone」>「Firmware version」を確認してください。「1.6」になっていれば、成功です。



最後になりましたが、アップデート前ではlocaleから日本語の選択が可能でしたが、アップデート後に日本語が選択できなくなりました!!
1.6で日本語使いたい場合には、どうすればよいのでだろうか。。もう少し調査して、日本語に対応しているアップデートイメージなど見つけられればと思っています。

2010年1月29日金曜日

Check The Status Of SD Card

[In English]
Today I wrote how to check the free space and status of SD Card on Android.

The following code is a simple way of checking if the free space is enough or not.

final double saveSize = (The file size);
File file = Environment.getExternalStorageDirectory();
StatFs statFs = new StatFs(file.getAbsolutePath());
final double freeSize = statFs.getFreeBlocks() * statFs.getBlockSize();
if (freeSize < saveSize) {
// There is not enough space in SD Card
} else {
// There is enough space in SD Card
}


If you want to make sure whether SD Card is inserted to the mobile device or not, you can use Environment class static method for it.

String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)){
// SD Card is mounted
} else {
// SD Card is not mounted
}

You can check the other status of SD Card as well as mount(insert) status,
so if you want to know it, please see the java doc.
for example, Read-Only(Environment.MEDIA_MOUNTED_READ_ONLY).



[In Japanese]
本日は、Android上でSDカードの空き容量やステータスの確認方法につて、ブログを書きました。

下記のコードは空き容量が十分であるかどうかを確認するための簡単な方法です。

final double saveSize = (ファイルサイズ);
File file = Environment.getExternalStorageDirectory();
StatFs statFs = new StatFs(file.getAbsolutePath());
final double freeSize = statFs.getFreeBlocks() * statFs.getBlockSize();
if (freeSize < saveSize) {
// 十分な空き容量なし
} else {
// 十分な空き容量があるため、ファイルを保存
}


また、その他にSDカードが端末に挿入さえているかどうかをチェックしたい場合は、Environmentクラスの
staticメソッドを使うことで確認できます。

String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)){
// SD Card is mounted
} else {
// SD Card is not mounted
}

マウント(挿入)されているかどうかのSDカードの状態確認以外にも色々と確認できますので、興味のある方は、Environmentクラスのjava docを参照してみてください。
例) 読み取り専用の場合:(Environment.MEDIA_MOUNTED_READ_ONLY)

2010年1月28日木曜日

introduced Hudson

[in English]
I introduced 'Hudson' which belongs to the genre of CI tool.
I found it that 'Hudson' is an extraordinary CI tool. There's three reasons.

1. EASY TO INTRODUCE. It's quite simple. The only thing I had to do is to deploy jar file on the servlet container. That's it.
In case of no servlet container, you need to install java and run hudson.jar( java -jar hudson.jar). That's all.

2. EASY TO USE. very simple to understand how to use.

3. HIGH FUNCTIONALITY. Hudson has many customizable functionality. You can set every configuration from the browser.





This time I introduced Hudson to deploy HTML files to my web server. Of course hudson can adapt to any kind of application; Web application, client-server-type application as well as static HTML.

I manage HTML files by SVN server and let hudson know where the SVN server is. So when I want to renew my web site, first commit HTML files to SVN server and second execute build on hudson from the browser. That's all. Don't you think it's easy, do you?

Why don't you think of introducing CI tool? It's gonna be very helpful.



[In Japanese]
HudsonというCIツールを導入してみました。CIツールの中ではかなりイケてるツールだと思います。理由は3つあります。

1.導入が簡単。導入の際に行う事は、jarファイルをサーブレットコンテナ上に配置するだけです。サーブレットコンテナがない環境でも、Javaをインストールしてhudsonを単体で起動するだけです。(java -jar hudson.jar)。

2.使いやすい。習得がとても簡単です。

3.高機能。設定項目がたくさん用意されていて、全てのjavascript:void(0)設定がブラウザ上から行えます。
今回はHTMLファイルをWebサーバに配置する目的でHudsonを導入しました。勿論、静的なHTMLファイルだけではなく、Webアプリケーションやクライアント-サーバ型のアプリケーションなど、何にでも使用できます。

私はHTMLファイルをSVNサーバで管理していて、HudsonにSVNサーバのURLを設定済みなので、ウェブサイトを更新したい時は、まず編集したHTMLファイルをSVNへコミットし、次にHudson上でビルドを実行するだけです。
簡単だと思いませんか?
興味があれば、CIツールを導入してみてはどうでしょうか。きっと役に立つと思います。

2010年1月22日金曜日

Sony Ericson Xperia X10 press conference




[in English]
Last Thursday, Sony Ericson and Docomo held the press conference for Xperia X10 in Japan. It consists of two parts. one is for mass media, the other is for Developers and Blogers. I joined it from second part. Some application Vendors exhibitted Android Application which will be released at the same time of Xperia X10 release.
Some of them are Location Based Service Applications and Cloud Applications, and some of them are movie and music applications for only high spec mobile phone like Xperia X10. I'll be watching some of them, and I'll report it later.


[In Japanese]
先週の木曜に、ソニーエリクソンとドコモがXperiaの端末発表会を開催しました。2部構成になっていて、1部はメディア向け、2部はブロガー及びデベロッパ向けでした。
私は、2部より参加したのですが、Xperiaの発売にあわせてリリースされるAndroid Applicationの展示がありました。位置情報やクラウド系のアプリのほか、Xperiaの高性能を活かした音楽と映像のアプリなどがありました。いくつかのアプリに注目して、正式リリース後にまたレポートしたいと思います。

2010年1月21日木曜日

Get HTC-Magic




[In English]
The other day I purchased HTC-Magic phone called HT-03A in Japan. As you know it's the only android phone in Japan for now.
In fact I've already owned Dev Phone. They are not exactly the same between HTC-Magic and Dev Phone from a functional point of view. That's why I wanted to get it.

Actually I found some differences between them in developing android application.
Now that I owned the both, I could develop better application and could find it easy to fix bugs.





[In Japanese]
先日、HTC-Magic携帯を購入しました。日本ではHTC-03Aと呼ばれており、現状では唯一のAndroid携帯です。
実は既にDev Phoneを所有していたのですが、ずっとHTC-03Aを欲しいと思っていました。というのも、両者は機能的に全く同じではないからです。実際、開発をしてる時に動作が異なる点をいくつか発見しました。

2台体制で、より品質のいいアプリが提供でき、かつバグ改修も簡単になるはずだと思ってます。

2010年1月16日土曜日

Android Frame-by-Frame animation

[in Englis]
Today I'll write the article about when I was in the trouble about Android Frame-by-Frame Animation using several png image files.

In the short, Frame-by-Frame animation is like a flipbook using picture files.

First, I tried to write animation codes referring to Android Developer Reference, but it didn't work.
so I looked into the cause of it, and then I studied that Frame-by-Frame animation must be started after onCreate/onResume is finished on Activity life cycle.
Translate or rotate animations can be started in onCreate/onResume, but Frame-by-Frame animation cannot be done.

How to start Frame-by-Frame animation is that starting it in onWindowFocusChanged.
(It is easy solution, so if I find the any other better solution I'll write blog about this)

I'll show the sample codes.

・main.xml

<framelayout id="@+id/FrameLayout01" android="http://schemas.android.com/apk/res/android" layout_width="wrap_content" layout_height="wrap_content">
<imageview id="@+id/ImageView01" layout_height="wrap_content" layout_width="wrap_content" layout_gravity="top" background="@anim/frame_anim">
</imageview>
</framelayout>


・frame_anim.xml

<animation-list id="animation_sample" android="http://schemas.android.com/apk/res/android" oneshot="false">
<item duration="100" drawable="@drawable/anim01">
<item duration="100" drawable="@drawable/anim02">
<item duration="100" drawable="@drawable/anim03">
<item duration="100" drawable="@drawable/anim04">
<item duration="100" drawable="@drawable/anim05">
</animation-list>


・AnimActivity.java

package com.sample.frameanim;

import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.widget.ImageView;

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

@Override
public void onWindowFocusChanged(boolean hasFocus) {
ImageView imageView1 = (ImageView) findViewById(R.id.ImageView01);
    AnimationDrawable animation1 =
(AnimationDrawable)imageView1.getBackground();
    if (hasFocus) {
      animation1.start();
    } else {
      animation1.stop();
    }
  }
}





[in Japanese]
pngファイルを複数使って、AndroidのFrame-by-Frameアニメーションをするサンプルアプリの作成で、はまったことを書きたいと思います。


Frame-by-Frameアニメーションとは、一言で言うと画像ファイルのパラパラ漫画です。(同一サイズの)複数の画像ファイルを次々と変えることでアニメーションを実現します。

先ず、Android Developer Referenceを参照して作ったのですが、全くアニメーション動作が開始されませんでした。
色々調べたところ、Frame-by-Frameアニメーションは、Activityのライフサイクルの中で、onCreate/onResumeが完了した後に実施する必要があるようです。
手っ取り早く動作を見たくて、他のtranslateやrotateのアニメーション同様に、onCreateの中でアニメーションをスタートしたのが原因でした。

取り急ぎの解決方法として
onWindowFocusChangedメソッド内で実行することです。
(他にも方法があれば追記していきたいと思います。)

下記は、onWindowFocusChangedメソッドを使って、Frame-by-Frameアニメーションを実現させたコードです。

・main.xml

<framelayout id="@+id/FrameLayout01" android="http://schemas.android.com/apk/res/android" layout_width="wrap_content" layout_height="wrap_content">
<imageview id="@+id/ImageView01" layout_height="wrap_content" layout_width="wrap_content" layout_gravity="top" background="@anim/frame_anim">
</imageview>
</framelayout>


・frame_anim.xml

<animation-list id="animation_sample" android="http://schemas.android.com/apk/res/android" oneshot="false">
<item duration="100" drawable="@drawable/anim01">
<item duration="100" drawable="@drawable/anim02">
<item duration="100" drawable="@drawable/anim03">
<item duration="100" drawable="@drawable/anim04">
<item duration="100" drawable="@drawable/anim05">
</animation-list>


・AnimActivity.java

package com.sample.frameanim;

import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.widget.ImageView;

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

@Override
public void onWindowFocusChanged(boolean hasFocus) {
ImageView imageView1 = (ImageView) findViewById(R.id.ImageView01);
    AnimationDrawable animation1 =
(AnimationDrawable)imageView1.getBackground();
    if (hasFocus) {
      animation1.start();
    } else {
      animation1.stop();
    }
  }
}