Archive for the ‘Android apps’ Category

アプリでSMSを受信したい

2011年6月11日

携帯へ何かを通知したい場合、日本のようにi-modeメールでプッシュ配信できない海外では、SMSを使うのが主流。サーバーからアプリに何かの情報を配信する場合も、この仕組みをつかうのが一番簡単だと思う。

★AndroidのSMSに関する資料

上に紹介したAPI Demoをビルドして検証しようとしたところ、なぜかSMSのデモがメニューからなくなっていた。調べてみると、自分のAndroid(Experia X10 mini: Android version 2.1 update)にあわせて設定したビルドターゲット、つまりAPI Level 7(=Version2.1 update)のAPI DemoにはSMS関連のソースが無かった(Level8と9にはある)。ビルドターゲットをAPI Level8 でAPI Demoのプロジェクトを作り直しすと、SMS関連のデモも動いた。

エミュレータにSMSを送るには、Eclipseで[Window]-[Open Perspective]-[DDMS]を開き、Emulator Controlから送信。

SMSを受信すると、メッセージを表示するウィンドウが現れ、さらにメッセージを読み上げる。SMSを受信する設定になっている間は、API Demo の画面を閉じても、SMSを受信するとメッセージを表示するウィンドウは現れる。

しかしSDKのリファレンスによると、SMS関連のクラスはAPI Level7でも使えるはずだ。API Level 8のAPI DemoのソースからSMS関連のソースをコピーしてビルドターゲットをAPI Level 7にしてビルドしてみた。

新規プロジェクトを作成し、SmsMessageReceiver.java と SmsReceivedDialog.java はそのままコピーしてPackage名だけを変更。プロジェクトのActivityクラスには、SmsMessageDemo.java の中身をそっくりコピー。res/values/strings.xml には、関連する文字列をコピー。res/layout/sms_demo.xml はそのままコピーしただけではビルドできなかったが、プロパティ layout_widthとlayout_heightの値 “match_parent” を “fill_parent” に置き換えてビルドできた。

・・・で、動かしてみるが、SMSを送っても反応しない。SmsMessageReceiver にブレークポイントを張って動かしてみたが、最初から最後まで止まらない。よくソースを見返してみると、SmsMessageReceiver を BroadcastReceiverとして追加するコードがない・・・。API Demo の元のソースをみてもない。しかし、上で紹介した http://www.androidcompetencycenter.com の記事を見て、Manufest.xmlで Receiver として設定する必要があることがわかった。API Demo の元のソースにもあったので、そこからコピー。さらに、元の Manufest.xml には SMSの機能に関する uses-permission も設定されていたので、それもコピー。これで SMS に反応するようになった。

しかし、SMS を受信してすぐに落ちてしまう・・・。ログを見ると、権限が足りなくてExceptionが発生している。SMS 関連の uses-permission は全てつけたはずだが・・・?デバッガで見てみると、SMS を受信した後で、電話帳から発信元番号の主を検索する処理が入っていて、ここで落ちていた。なるほど!電話帳のアクセス件が必要だったわけだ。確かに元の Manufest.xml にはあったので、それをコピーして追加。これで正常に動くようになった。SMS の受信だけでなく、電話帳の検索方法まで紹介してくれていた。なんて親切なサンプルコードなんだ!(>_<)

ちなみにiPhoneでは、SMSの送信はできるが受信はできないらしい。アプリにプッシュ式で通知する仕組みとしては、Local and Push Notification というのがあるようだが、ハードルが高そうなので、今は止めておく。

★iPhoneのSMSとLocal and Push Notification に関する資料

ゴルフのスコアカウンター(Android版)

2011年4月30日

ゴルフのスコアをカウントするための、簡単なアプリを作成した。(私のようにダブルパー以上を普通に叩く人は、打数を数えるのが大変なので、こんなのが必要!)各ホールの打数を記録するとともに、トータルスコアとPAR数を引いたオーバーの値も出すようにする。

ソース

●画面のレイアウト

layout.xml

レイアウト

一番底がLinearLayoutで、上からホール数表示エリア、PAR表示エリア、スコア表示エリア、トータルスコア表示エリアとした。
ホール数表示エリア内をRelativeLayoutにしてホール数を増減するボタンを両端に、ホール数表示のラベル(TextView)を真ん中に配置した。
PAR表示エリアは、PAR数を選択するSpinnerのみ。
スコア表示エリアは、これもRelativeLayoutにしてスコアを増減するボタンを両端に、真ん中をさらにLinearLayoutにして上にこのホールのスコア、下にPARを引いた値を表示。
トータルスコア表示エリアはラベル(TextView)のみである。

●クラス構成

Activity の派生クラスのGolfscntという名前のクラスのみ。このクラスのonCreateメソッド内で、各コントロールのイベントハンドラを一時クラスとして実装している。

●課題

PARを選択するspinnerの字を他のにあわせて大きくしたいのだが、textSizeを変えても大きくならなかった。

課題という訳ではないが、実際に使ってみたとことろ・・・明るい野外では液晶が見にくくて、結局ほとんど使えなかった。残念・・・orz

ダウンロードはこちら

iPhoneSDKのサンプルMoveMeをAndroidに移植

2011年3月6日

iPhoneSDKのサンプルMoveMeをAndroidに移植してみた。ソースはこちら

左がオリジナル(iPhone版)、右が移植したもの。

(ならべて見ると・・・大きさが違い過ぎだが・・・気にしない・・・ )

MoveMeというプログラムは、次のような簡単なプログラムである。

  • 最初に画面中央にメッセージ(短い挨拶文)が書かれたボタンが表示される。
  • ボタンをタッチすると少し膨らみ、ボタンの中心はタッチされた位置に移動する。
  • ボタンはドラッグして移動され、指を離すと中央に戻る。中央に戻ったとき、勢いでボタンがはねるような動きをする。
  • ボタン以外の部分をダブルクリックすると、メッセージの言語が変わる。

Viewの構成

iPhone版ではメインの親であるMoveMeView上のタッチされた位置に、子であるPlacardView(ボタン)を表示する。PlacardViewは親画面内の座標で位置指定される。Androidで小画面(コントロールも含む)の位置指定はLayoutManagerに依存する。LayoutManagerもViewを継承するので、これが親画面といえる。座標で位置指定するにはLayoutManagerとしてAbsoluteLayoutを使用する必要があるが、実はこのAbsoluteLayoutの使用は推奨されていない。これはAndroid(だけでなく一般的なJavaプログラムにもいえることだが)ではデバイスにより画面サイズが異なるため、位置を座標で指定すると画面からはみ出たり、逆に小さ過ぎたりする可能性があるため。一般にLayoutManagerは親画面に対する小画面の相対位置を指定し、デバイスの画面サイズにあわせて、小画面やコントロールを自動的に最適な場所に配置する。ただしこのプログラムでは、小画面は画面のタッチで位置指定されるので、画面サイズの影響を気にする必要はなく、AbsoluteLayoutでも問題なかった。

クラスの構成

iPhone版で定義されたClassと、Android版のClassの対応は以下のようになった。

  • MoveMeAppDelegate → なし(Delegateの仕組みがない)
  • MoveMeView(メインの画面) → MoveMe内で使用されるAbsoluteLayoutクラス。
  • PlacardView(ボタン) → PlacardView

Animationの使用

ボタンを最初にクリックした際にボタンがふくらむ動作と、ドラッグされたボタンから指を離すと中心に戻り、反動で少し揺れる動作はアニメーションを使用した。SDKのサンプルではXMLファイルで定義するアニメーションの例が多いが、今回はアニメーションの位置が動的に変わるため、XMLだけでなく、プログラムによる定義も使用した。

↓↓↓Animation定義のコード↓↓↓

	//animate moving to center
	final long DURATION_ANIM1 = 300;
	TranslateAnimation move_center = new TranslateAnimation(
			TranslateAnimation.ABSOLUTE, x - mCenter.x,
			TranslateAnimation.RELATIVE_TO_SELF, 0,
			TranslateAnimation.ABSOLUTE, y - mCenter.y,
			TranslateAnimation.RELATIVE_TO_SELF, 0);
	move_center.setDuration(DURATION_ANIM1);
	move_center.setStartTime(Animation.START_ON_FIRST_FRAME);
	move_center.setInterpolator(new LinearInterpolator());
	//animate bouncing
	TranslateAnimation bounce = new TranslateAnimation(
			(float)0,
			(float)(mCenter.x - (mPtEnd.x + WIDTH/2))/20,
			(float)0,
			(float)(mCenter.y - (mPtEnd.y + HEIGHT/2))/20);
	bounce.setDuration(200);
	bounce.setStartTime(Animation.START_ON_FIRST_FRAME);
	bounce.setStartOffset(DURATION_ANIM1);
	bounce.setInterpolator(new CycleInterpolator((float) 2.75));
	//AnimationSet consist of above two animation
	AnimationSet go_center_bounce = new AnimationSet(false);
	go_center_bounce.addAnimation(move_center);
	go_center_bounce.addAnimation(bounce);
	this.setAnimation(go_center_bounce);
	go_center_bounce.startNow();

イベントハンドラ

iPhone版では親画面であるMoveMeViewにイベントハンドラが定義されているが、Android版では、親画面となるAbsoluteLayoutにListenerを追加し、そのListener内にイベントハンドラを定義することになる。1つよくわからないのが、ダブルクリックの判定方法で、今回は前回クリックされてから何ms以内に次のクリックがあればダブルクリックと判定している。あまりスマートでない感じがするので、もっといい判定方法を調べなければ。

AbsoluteLayoutによるボタンの位置指定

AbsoluteLayoutのLayoutParamsが位置の属性を持つ。ということは、このLayoutParamsの参照を保持しておき、属性を変更することで位置を変更できるかと思いきや、位置を指定するたびにAbsoluteLayoutのsetLayoutParams()を呼び出す必要があった。

まとめ

今回のサンプルは非常に簡単だったので、アニメーションの使用を除けば、一般的なJavaプログラムとそれほど変わらず、Androidだからということで特別に意識するところはなかった。Javaが使えるので、iPhoneよりは敷居が低そうだ。

Android SDK のHello, World! ・・・あれ?動かない・・・

2011年1月29日

Android SDKのTutrialを試してみた。

http://developer.android.com/resources/tutorials/hello-world.html

指示通りにプロジェクトを作成し、ソースを編集して、実行。

“Hello, World!”って文字を表示するだけだから、まず大丈夫だと思っていたら・・・

あれ?? 動かない・・・と思っていたら

画面が変わった! やっと起動したらしい。でも”Hello,World!”は?

焦っていろいろボタンを押してみると

“MENU” ボタンで出てきた!