2010年6月13日日曜日

Androidで画面の縦横が切り替わった時にActivityが再起動されない方法

AndroidのActivityのlifecycleは
http://developer.android.com/guide/topics/fundamentals.html
の説明にあるようにonCreateから始まってonDestroyで終わります。
Activityが起動すると、
onCreate -> onStart -> onResume
の順序で、Activityが動作します。
終了時には、
onPause -> onStop -> onDestroy
の順序でActivityが終わります。
途中、割り込みなどで、推移します。

画面の縦横が切り替わった時には
onCreate -> onStart -> onResume -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume
の順序で呼ばれます。
これは、画面の縦横変化によって、画面を再構成する必要があるからです。

だけど、Activityによっては、これでは困る場合があります。
そんなときは、AndroidManifest.xmlの対応するActivityに
android:configChanges="orientation"
を加えましょう。
すると、画面の縦横が切り替わってもonPause以降は呼ばれません。
その代わりにonConfigurationChangedが呼ばれます。

2010年6月9日水曜日

AndroidでBluetooth~Discoveryまで~


package jp.ac.hoge.android.bluetooth;

import java.util.Set;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.TextView;

public class BluetoothTestActivity extends Activity {
private static final int REQUEST_ENABLE_BT = 1;
private static final int REQUEST_STATE_CHANGE_BT = 2;
private TextView tv_result = null;
private BluetoothAdapter mBluetoothAdapter = null;
private BluetoothReceiver mBluetoothReceiver = null;

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

tv_result = (TextView) findViewById(R.id.tv_result);
tv_result.setText("");

checkBluetooth();
}

private void checkBluetooth() {
tv_result.append("Step 1:Bluetoothの利用可能状態\n");
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
tv_result.append("Bluetoothはサポートされてません\n");
} else {
tv_result.append("Bluetoothはサポートされています\n");
if (mBluetoothAdapter.isEnabled()) {
tv_result.append("Bluetoothは利用可能です\n");
getLocalInformation();
} else {
Intent enableBTIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBTIntent, REQUEST_ENABLE_BT);
Intent stateChangedBTIntent = new Intent(
BluetoothAdapter.ACTION_STATE_CHANGED);
startActivityForResult(stateChangedBTIntent,
REQUEST_STATE_CHANGE_BT);
}
}
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == RESULT_OK) {
tv_result.append("Bluetoothが利用可能になりました\n");
getLocalInformation();
} else if (resultCode == RESULT_CANCELED) {
tv_result.append("Bluetoothは利用不可です\n");
}
} else if (requestCode == REQUEST_STATE_CHANGE_BT) {
switch (resultCode) {
case BluetoothAdapter.STATE_TURNING_ON:
tv_result.append("STATE_TURNING_ON\n");
break;
case BluetoothAdapter.STATE_ON:
tv_result.append("STATE_ON\n");
break;
case BluetoothAdapter.STATE_TURNING_OFF:
tv_result.append("STATE_TURNING_OFF\n");
break;
case BluetoothAdapter.STATE_OFF:
tv_result.append("STATE_OFF\n");
break;
}
}
}

private void getLocalInformation() {
tv_result.append("\nStep 2:自機Bluetoothの調査\n");

tv_result.append(mBluetoothAdapter.getName() + ":"
+ mBluetoothAdapter.getAddress() + "\n");
switch (mBluetoothAdapter.getScanMode()) {
case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
tv_result.append("SCAN_MODE_CONNECTABLE:");
break;
case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
tv_result.append("SCAN_MODE_CONNECTABLE_DISCOVERABLE:");
break;
case BluetoothAdapter.SCAN_MODE_NONE:
tv_result.append("SCAN_MODE_NONE:");
break;
}
switch (mBluetoothAdapter.getState()) {
case BluetoothAdapter.STATE_OFF:
tv_result.append("STATE_OFF\n");
break;
case BluetoothAdapter.STATE_ON:
tv_result.append("STATE_ON\n");
break;
case BluetoothAdapter.STATE_TURNING_OFF:
tv_result.append("STATE_TURNING_OFF\n");
break;
case BluetoothAdapter.STATE_TURNING_ON:
tv_result.append("STATE_TURNING_ON\n");
break;
}
findPairedDevices();
}

private void findPairedDevices() {
tv_result.append("\nStep 3:登録済みのBluetoothの調査\n");

Set<BluetoothDevice> pairedDevices = mBluetoothAdapter
.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
tv_result.append(device.getName() + ":" + device.getAddress()
+ ":" + device.getBluetoothClass() + "\n");
}
} else {
tv_result.append("登録されているBluetoothデバイスはありません\n");
}
discoverDevices();
}

private void discoverDevices() {
tv_result.append("\nStep 4:Bluetoothデバイスの探索\n");

mBluetoothReceiver = new BluetoothReceiver();
registerReceiver(mBluetoothReceiver, new IntentFilter(
BluetoothDevice.ACTION_FOUND));
mBluetoothAdapter.startDiscovery();
tv_result.append("探索開始\n");
}

class BluetoothReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
tv_result.append("Bluetoothデバイスを発見\n");
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
tv_result.append(device.getName() + ":" + device.getAddress()
+ ":" + device.getBluetoothClass() + "\n");
}
}
}
}

AndroidManifest.xml
<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>

BLUETOOTH_ADMINはstartDiscovery()に必要です。

2010年6月7日月曜日

Nexus One搭載センサー 

  • TYPE_ACCELEROMETER (加速度センサー)○
  • TYPE_GYROSCOPE (ジャイロセンサー)×
  • TYPE_LIGHT(光センサー)○
  • TYPE_MAGNETIC_FIELD(磁気センサー)○
  • TYPE_ORIENTATION(方位センサー)○
  • TYPE_PRESSURE(圧力センサー)×
  • TYPE_PROXIMITY(近接センサー)○
  • TYPE_TEMPERATURE(温度センサー)×

AndroidのHttpのPostでもはまる

AndroidからHttpでPostするときのアプリです。

package jp.ac.hoge.android.httppost;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class HttpPostActivity extends Activity {
private static final String URI = "http://hoge/http_post_test.php";

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

Button btn_sbmit = (Button) findViewById(R.id.btn_sbmit);
btn_sbmit.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO 自動生成されたメソッド・スタブ
EditText et_string = (EditText) findViewById(R.id.et_string);
String value = et_string.getText().toString();
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(URI);
List<NameValuePair> nameValuePair = new ArrayList<NameValuePair>(
1);
nameValuePair.add(new BasicNameValuePair("str", value));

try {
httppost.setEntity(new UrlEncodedFormEntity(nameValuePair));
HttpResponse response = httpclient.execute(httppost);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
response.getEntity().writeTo(byteArrayOutputStream);
TextView tv_result = (TextView) findViewById(R.id.tv_result);
tv_result.setText(byteArrayOutputStream.toString());

} catch (UnsupportedEncodingException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
} catch (IOException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
}
});
}
}

httpclient.execute(httppost)でこけますが、LogにINTERNETのpermissionがないよと言われるので、AndroidManifest.xmlに

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

を付け加えます。


サーバアプリはPOSTで投げた文字列をただ2回出力するだけです。

2010年6月6日日曜日

AndroidのWifiのscanStartではまる

AndroidでWifiをScanするプログラムです。

package jp.ac.hoge.android.wifi;

import java.util.List;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class WifiActivity extends Activity implements OnClickListener {
private TextView tv_search_result;
private WifiManager wifi_mng;
private WifiReceiver wifi_rec;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn_start_search = (Button) findViewById(R.id.btn_start_search);
btn_start_search.setOnClickListener(this);
}

public void onClick(View v) {
// TODO 自動生成されたメソッド・スタブ
if (v.getId() == R.id.btn_start_search) {
tv_search_result = (TextView) findViewById(R.id.tv_search_result);
wifi_mng = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifi_rec = new WifiReceiver();
registerReceiver(wifi_rec, new IntentFilter(
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
wifi_mng.startScan();
tv_search_result.setText("スキャン開始\n");
}
}

class WifiReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
// TODO 自動生成されたメソッド・スタブ
StringBuffer sb = new StringBuffer();
List<ScanResult> result_list = wifi_mng.getScanResults();
for (int i = 0; i < result_list.size(); i++) {
sb.append(new Integer(i + 1).toString() + ".");
sb.append((result_list.get(i)).toString());
sb.append("\n");
}
tv_search_result.setText(sb);
}
}
}

このままだとstartScanで落ちてしまいます(もちろんエミュレータでは動かないのので実機Nexous Oneで)。
なので、AndroidManifext.xmlに

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

の権限を追加します(BREWみたい)。Bluetoothも同じような権限があるみたいだけどまだ未調査。



研究室のデスク周りで6つAPが見つかりました。
SSIDにはアクセスポイント名、BSSIDにはMACアドレス、capabilitiesには暗号化などの方式が表示されます。

inSSIDerみたいなのもすぐできそう。すでにあるかも。