アプリの全体構成
アプリのプログラムは下記の6つのクラスで構成される。
KameRoboAlarm |
Activityを継承するメインになるクラス。
アラームの設定と解除、タッチパネルイベントの受け取り、robocontライブラリとのインターフェースとなる。(下記参照)
|
---|---|
ClockImage |
短針のみのアナログ時計の表示を行うクラス。(下記参照)
|
Sound |
サウンドを管理するクラス。
|
WakeupImage |
タイマー起動し、カメロボをコントロール中に表示される背景を表示するクラス。
|
Updatable |
(下記参照)
|
UpdateHandle |
NDK上のMobRoboライブラリを呼び出す為のインターフェースクラス。(下記参照)
|
アナログ時計処理(ClockImage)
マウスで操作可能な短針のみのアナログ時計を実装する。
背景画像、文字盤画像、短針画像、セットボタン、キャンセルボタンを表示して、起動時間は画面上の短針の位置でセットできるようにする。
画面上の文字盤、セットボタン、キャンセルボタンの処理もこのクラスで行う
5種類の画像を準備して、/res/drawableに置く。
- 背景画像(kame_haikei.jpg)
- 文字盤(kame_panel.png)
- 短針(kame_hand.png)
- セットボタン(kame_set_1.png, kame_set_2.png)
- キャンセルボタン(kame_cancel_1.png, kame_cancel_2.png)
画像ファイルを読み込む。
bg = BitmapFactory.decodeResource(getResources(), R.drawable.kame_haikei); // 背景clock = BitmapFactory.decodeResource(getResources(), R.drawable.kame_panel); // 文字盤
hand = BitmapFactory.decodeResource(getResources(), R.drawable.kame_hand); // 針
setBtn1 = BitmapFactory.decodeResource(getResources(), R.drawable.kame_set_1); // セットボタン
setBtn2 = BitmapFactory.decodeResource(getResources(), R.drawable.kame_set_2); // セットボタン
cancelBtn1 = BitmapFactory.decodeResource(getResources(), R.drawable.kame_cancel_1); // キャンセルボタン
cancelBtn2 = BitmapFactory.decodeResource(getResources(), R.drawable.kame_cancel_2); // キャンセルボタン
各画像のサイズも取得しておく。
bgW = bg.getWidth(); // 背景の画像サイズbgH = bg.getHeight();
clockW = clock.getWidth(); // 文字盤の画像サイズ
clockH = clock.getHeight();
setBtnW = setBtn1.getWidth(); // セットボタンの画像サイズ
setBtnH = setBtn1.getHeight();
cancelBtnW = cancelBtn1.getWidth(); // キャンセルボタンの画像サイズ
cancelBtnH = cancelBtn1.getHeight();
描画処理
背景画像と文字盤を画面中央に描画する。
int cy = height / 2;
int x = cx - bgW / 2; // 背景の中心は画面の真ん中にする
int y = cy - bgH / 2;
canvas.drawBitmap(bg, x, y, paint); // 背景を描画する
x = cx - clockW / 2; // 文字盤の中心は画面の真ん中にする
y = cy - clockH / 2;
canvas.drawBitmap(clock, x, y, paint); // 文字盤を描画する
短針は設定時刻に合わせて回転し、描画します。
float h = hou % 12;float m = min;
float a = (360f / 12f * h) + (360f / 12f / 60f * m) - 90; // 針の角度を計算する。(キャラが横向きなので90度補正する)
Matrix matrix = new Matrix();
matrix.postRotate(a); // 針用の回転マトリックス
int ang = (int)(a - 45 + 360) % 360; // 左上
x = (int)(Math.sin(ang * Math.PI / 180) * handL); // 針の左上の位置を計算する
y = (int)(Math.cos(ang * Math.PI / 180) * handL);
matrix.postTranslate(cx + x, cy - y); // マトリックスに対して移動を設定する
canvas.drawBitmap(hand, matrix, paint); // 針を描画する
セットボタンとキャンセルボタンを描画します。
setBtnX = cx - clockW / 2; // 文字盤の左側に合わせるsetBtnY = cancelBtnY = cy + clockH / 2; // 文字盤の下
cancelBtnX = cx + clockW / 2 - cancelBtnW; // 文字盤の右側に合わせる
canvas.drawBitmap(setBtn1, setBtnX, setBtnY, paint); // セットボタンを描画
canvas.drawBitmap(cancelBtn1, cancelBtnX, cancelBtnY, paint); // キャンセルボタンを描画
タッチ位置の判断。表示した各画像の表示位置と画像サイズに合わせ、何の操作をしてるのか判断する。文字盤がタッチされている場合、時間に変換し、画面を再描画します。
* タッチ位置から時間に変換し、画面再描画をリクエストする。
* @param tx タッチ位置X
* @param ty タッチ位置Y
* @retun 0=文字盤 1=セット 2=キヤンセル -1=それ以外
*/
public int setTouchPos(float tx, float ty){
if (0 != width && 0 != height){
tx -= (Alarm.windowWidth - width); // タッチ位置と表示位置のズレを補正
ty -= (Alarm.windowHeight - height);
float centerX = width / 2; // 画面中心
float centerY = height / 2;
float x = centerX - tx;
float y = centerY - ty;
float w = clockW / 2;
if ((w*w) >= (x*x + y*y)){ // 文字盤の中
double rad = Math.atan2(-x, y);
int ang = ((int)(rad * 180 / Math.PI) + 360) % 360;
int h = ang / 30;
int m = (ang - h*30) * 2;
setTime(h, m); // 時間をセット
return 0; // 文字盤
}
else{ // 文字盤以外
if (setBtnX <= tx && (setBtnX+setBtnW) >= tx
&& setBtnY <= ty && (setBtnY+setBtnH) >= ty){
return 1; // セットボタン
}
if (cancelBtnX <= tx && (cancelBtnX+cancelBtnW) >= tx
&& cancelBtnY <= ty && (cancelBtnY+cancelBtnH) >= ty){
return 2; // キャンセルボタン
}
}
}
return -1; // その他
}
メイン処理 (KameRoboAlarm)
アプリ起動後最初に呼ばれるクラスです。
ClockImageクラスを呼び出し、現在時刻を表示します。
.
(中略)
.
mClockImage = new ClockImage(this); // 時計UI
setContentView(mClockImage); // 表示を時計UIに移す
mClockImage.setTime(mCalendar.get(Calendar.HOUR_OF_DAY), mCalendar.get(Calendar.MINUTE));
タッチイベントを検出し、ClockImageクラスにタッチ位置を渡す。
public boolean onTouchEvent(MotionEvent event){int act = event.getAction();
if (act == MotionEvent.ACTION_DOWN // タッチした
|| act == MotionEvent.ACTION_MOVE){ // 移動した
if (mode){
float touchX = event.getX();
float touchY = event.getY();
int r = mClockImage.setTouchPos(touchX, touchY);
セットボタンが押された時は、時計表示部の設定時間を取り出し、再起動時間をセットし、アプリを終了します。
Calendar mCalendar = new GregorianCalendar(); // 現在時刻を取得Date trialTime = new Date();
mCalendar.setTime(trialTime);
int sh = mClockImage.getHours() % 12;
int sm = mClockImage.getMinutes();
int ch = mCalendar.get(Calendar.HOUR_OF_DAY) % 12;
int cm = mCalendar.get(Calendar.MINUTE);
int h = ((sh+24) - ch) % 12;
int m = sm - cm;
if (0 > m){
m += 60;
h--;
if (0 > h) h += 12;
}
if (0 != h || 0 != m){
String awt = "";
if (0 == h){
awt = m+"分後";
}
else{
awt = h+"時間"+m+"分後";
}
mCalendar.add(Calendar.HOUR, h);
mCalendar.add(Calendar.MINUTE, m);
String wt = ""+mCalendar.get(Calendar.HOUR_OF_DAY)+"時"+ mCalendar.get(Calendar.MINUTE)+"分";
Toast.makeText(this, awt+"の"+wt+"に起動します。", Toast.LENGTH_LONG).show();
}
long tm = mCalendar.getTimeInMillis();
setTime(tm);
setAlarm(tm);
finish();
AlarmManagerに対して、アラームの設定を行う。
private void setAlarm(long time) {mManager.set(AlarmManager.RTC_WAKEUP, time, pendingIntent());
mode = false;
setMode(mode);
}
アラームの設定時刻に発生するインテントの作成
private PendingIntent pendingIntent() {Intent i = new Intent(getApplicationContext(), KameRoboAlarm.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, i, 0);
return pi;
}
MobRoboLibインターフェース(Updatable, UpdateHandle)
NDK上のMobRoboライブラリを呼び出す為のインターフェースクラス
package名 |
com.robo;
|
---|
class名 |
Updatable
update() のダミー
|
---|
class名 |
UpdateHandle
親:Handler
|
---|
- UpdateHandler(Updatable updatable);
- インストラクタ(親の設定)
- void handleMessage(Message msg);
- イベント受信 上記 Updateble::update() を呼ぶ。
- void sleep(long sleepTime);
- 次の呼び出し時間設定
- void kill();
- メッセージの削除