Googleのアカウント情報を保存する〜スケジュール管理ソフトをS!アプリで作ってみよう(その29)

前回で、GoogleのAuthCodeを取得できた。この情報をRecordStoreに保存するようにする。

アカウント情報を入力するフォームは、単純にした。


package jp.dip.ettem.scheduler;

import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemStateListener;
import javax.microedition.lcdui.TextField;

public class GCalAuthForm extends Form implements ItemStateListener {
private TextField account;
private final int MAIL_ADDR_LEN = 256; // メールアドレスの長さ(TODO:RFCを調べる)
private TextField passwd;
private final int PASSWD_LEN = 64; // パスワードの長さ(TODO:Googleのアカウントを調べる)

private GCalAccount gCalAccount;

public GCalAuthForm(GCalAccount gCalAccount) {
super("GCal Account");
this.gCalAccount = gCalAccount;

setItemStateListener(this);

this.account = new TextField("Mail", gCalAccount.account, MAIL_ADDR_LEN, TextField.ANY);
append(this.account);

this.passwd = new TextField("Password", gCalAccount.passwd, PASSWD_LEN, TextField.PASSWORD);
append(this.passwd);
}

public void itemStateChanged(Item changedItem) {
if (changedItem == account) {
gCalAccount.account = account.getString();
} else if (changedItem == passwd) {
gCalAccount.passwd = passwd.getString();
}
}

}

メインのクラスから、入力フォームを呼び出すようにしている。


package jp.dip.ettem.scheduler;

import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import javax.microedition.rms.*;

import jp.dip.ettem.util.MessageDialog;

/**
* メインのクラス。
* 初期化、画面の遷移の制御をする。
*/
public class Scheduler extends MIDlet implements CommandListener {
private Display display;

private MainCanvas mainScr; // メインの画面
private Command exitCommand; // アプリ終了コマンド

private GCalAuthForm authForm; // Google Calendarアカウント設定用
private Command gCalConfCommand; // Google Calendar設定画面呼び出し
private Command gCalOkCommand; // アカウント設定完了
private GCalAccount gCalAccount;
private RecordStore gCalRecordStore; // Google Calendar設定内容保存用

private RecordStore scheduleRecordStore; // 予定格納用


public Scheduler() {
try {
// 予定のRecordStoreのオープン
scheduleRecordStore = RecordStore.openRecordStore("ScheduleBook", true);
Events.setRecordStore(scheduleRecordStore);

// Google Calender用の設定のRecordStoreのオープン
gCalRecordStore = RecordStore.openRecordStore("GGcalSetting", true);
GCal.setRecordStore(gCalRecordStore);
GCal.readAccount();
GCal.setAuthCode();

/*
* 画面制御関連
*/
display = Display.getDisplay(this);
MessageDialog.display = display;

/*
* コマンドの設定
*/
// 終了コマンドの設定
exitCommand = new Command("Exit", Command.EXIT, 2);
// Google Calendareの設定
gCalConfCommand = new Command("GCal", Command.ITEM, 1);

/*
* メインの画面の設定
*/
mainScr = new MainCanvas(Display.getDisplay(this));
mainScr.addCommand(exitCommand);
mainScr.addCommand(gCalConfCommand);
mainScr.setCommandListener(this);

/*
* Googleカレンダーのアカウント設定用画面
*/
gCalAccount = new GCalAccount();
gCalAccount.account = GCal.account;
gCalAccount.passwd = GCal.passwd;
authForm = new GCalAuthForm(gCalAccount);
gCalOkCommand = new Command("OK", Command.OK, 1);
authForm.addCommand(gCalOkCommand);
authForm.setCommandListener(this);

} catch (RecordStoreException e) {
// RecordStoreがopenできなければ、いきなりアプリ終了
// TODO: アプリ終了のメッセージの表示を実装する事。
scheduleRecordStore = null;
try {
destroyApp(false);
notifyDestroyed();
} catch (MIDletStateChangeException midletStChanExc) {

}
}

}

protected void destroyApp(boolean arg0) throws MIDletStateChangeException {

}

protected void pauseApp() {

}

protected void startApp() throws MIDletStateChangeException {
display.setCurrent(mainScr);
}

public void commandAction(Command command, Displayable displayable) {
if (command == exitCommand) {
try {
try {
scheduleRecordStore.closeRecordStore();
gCalRecordStore.closeRecordStore();
} catch (RecordStoreException e) {
// RecordStoreをcloseできなくても対応のしようがない。
// TODO: メッセージだけでも表示する事。
}
destroyApp(false);
notifyDestroyed();
} catch (MIDletStateChangeException e) {

}
} else if (command == gCalConfCommand) {
display.setCurrent(authForm);
} else if (command == gCalOkCommand) {
GCal.account = gCalAccount.account;
GCal.passwd = gCalAccount.passwd;
GCal.writeAccount();
GCal.setAuthCode();

display.setCurrent(mainScr);
}

}
}

アカウント情報の保存はGCalクラスで行っている。


package jp.dip.ettem.scheduler;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.Vector;

import javax.microedition.io.*;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;

/**
* Google Calenderと連携するためのクラス
*/
public class GCal implements GCalConstants {
static String account = new String();
static String passwd = new String();
private static String authCode;

private static RecordStore gCalSettingRecordStore;
private static final int ACCOUNT_RECORD_ID = 1;
private static final int PASSWD_RECORD_ID = 2;


/**
* 設定を保存するRecordStoreを設定します。
* @param scheduleRecordStore
*/
static void setRecordStore(RecordStore settingRecordStore) {
gCalSettingRecordStore = settingRecordStore;
}

/**
* RecordStoreからアカウント情報を読み込みます。
*
*/
static void readAccount() {
byte[] record;
try {
record = gCalSettingRecordStore.getRecord(ACCOUNT_RECORD_ID);
if (record != null) {
account = new String(record);
}

record = gCalSettingRecordStore.getRecord(PASSWD_RECORD_ID);
if (record != null) {
passwd = new String(record);
}
} catch (RecordStoreException e) {

}
}

/**
* RecordStoreにアカウント情報を書き込みます。
*
*/
static void writeAccount() {
byte[] record;
try {
record = account.getBytes();
if (gCalSettingRecordStore.getNumRecords() < 1) {
gCalSettingRecordStore.addRecord(record, 0, record.length);
} else {
gCalSettingRecordStore.setRecord(ACCOUNT_RECORD_ID, record, 0, record.length);
}

record = passwd.getBytes();
if (gCalSettingRecordStore.getNumRecords() < 2) {
gCalSettingRecordStore.addRecord(record, 0, record.length);
} else {
gCalSettingRecordStore.setRecord(PASSWD_RECORD_ID, record, 0, record.length);
}
} catch (RecordStoreException e) {

}
}

/**
* AuthCodeを設定します。
*
*/
static void setAuthCode() {
if (account == "" || passwd == "") {
return;
}

Thread authThread = new Thread () {
public void run () {
authCode = getAuthCode(account, passwd);
}
};
authThread.start();
}

/**
* Client Loginのための、AuthCodeを返します。
*
* @param eMail GoogleのログインのためのE-Mailアドレス
* @param passwd Googleのアカウントのパスワード
* @return
*/
private static String getAuthCode(String eMail, String passwd) {
String authCode = null;
HttpConnection connection = null;
OutputStream oStream = null;
InputStream iStream = null;

try {
// 接続先は、Googleではなく、私のサーバを指定。(しかもHTTPで接続)
// Googleが使っているSSL認証局に、Softbank Mobileが対応したら変更する予定。
connection = (HttpConnection) Connector.open(AUTH_URL);

connection.setRequestMethod(HttpConnection.POST);
byte[] postData =("Email=" + eMail + "&Passwd=" + passwd
+ "&source=jp.dip.ettem-scheduler-1&service=cl\r\n").getBytes();
connection.setRequestProperty("Content-Length", String.valueOf(postData.length));
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

oStream = connection.openOutputStream();
oStream.write(postData);

iStream = connection.openInputStream();
int len = (int) connection.getLength();
ByteArrayOutputStream content = getContent(iStream, len);

String contentStr = content.toString();

if (contentStr.indexOf("Auth=") > 0) {
authCode = contentStr.substring(contentStr.indexOf("Auth=") + "Auth=".length(),
contentStr.length() - 1);
}
} catch (IOException e) {

} finally {
try {
if (oStream != null) {
oStream.close();
}
if (iStream != null) {
iStream.close();
}
if (connection != null) {
connection.close();
}
} catch (IOException e) {
// 何もしない
}
}

return authCode;
}

/**
* HTTPのボディ部分を返します。
* @param iStream HTTPのボディ部分の入力ストリーム
* @param length HTTPのレスポンスのcontentの長さ(byte数)
* @return ボディ部分のByteArrayOutputStream
* @throws IOException
*/
static ByteArrayOutputStream getContent(InputStream iStream, int length)
throws IOException {
ByteArrayOutputStream oStream = new ByteArrayOutputStream();

if (length > 0) {
int actual = 0;
int bytesread = 0 ;
byte[] data = new byte[length];
while ((bytesread != length) && (actual != -1)) {
actual = iStream.read(data, bytesread, length - bytesread);
bytesread += actual;
}
oStream.write(data, 0, length);
} else {
int ch;
while ((ch = iStream.read()) != -1) {
oStream.write(ch);
}
}

return oStream;
}

}