UnityもVisual Studioも触ったことのなかった筆者が、Unity公式キャラクターである『ユニティちゃん』を使ってHololens開発をしてみます。その第1回目としてユニティちゃんをHoloLensで表示してみます。
UnityもVisual Studioも触ったことのなかった筆者が、Unity公式キャラクターである『ユニティちゃん』を使ってHololens開発をしてみます。その第1回目としてユニティちゃんをHoloLensで表示してみます。
| 連載目次 |
|
Part 2: 【HoloLens開発】日本での発売に備える実機開発 - 基礎知識編 - ←本記事
Part 8: 【HoloLens開発】ユニティちゃんとHoloLensで戯れる - シェアリング編2 - (予定)
|
本記事目次
|
| 連載目次 |
|
Part 2: 【HoloLens開発】日本での発売に備える実機開発 - 基礎知識編 - ←本記事
Part 8: 【HoloLens開発】ユニティちゃんとHoloLensで戯れる - シェアリング編2 - (予定)
|
本記事目次
|
| 連載目次 |
Part 1: 【HoloLens開発】日本での発売に備える実機開発 - 体験編 - ←本記事
Part 8: 【HoloLens開発】ユニティちゃんとHoloLensで戯れる - シェアリング編2 - (予定)
|
| 連載目次 |
Part 1: 【HoloLens開発】日本での発売に備える実機開発 - 体験編 - ←本記事
Part 8: 【HoloLens開発】ユニティちゃんとHoloLensで戯れる - シェアリング編2 - (予定)
|
![]() |
| http://www.grocerycrud.com/より抜粋 |
サービス名
|
UUID
|
説明
|
Generic Access
|
1800
|
デバイス名などの情報取得
|
Immediate Alert
|
1802
|
アラームを鳴らす
|
Link Loss
|
1803
|
接続が切れたときの挙動を設定する
|
Tx Power
|
1804
|
BLEの送信のパワー
|
Battery Service
|
180f
|
バッテリーの状態
|
public static final UUID ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
public static final UUID ALERT_LEVEL_UUID = UUID.fromString("00002a06-0000-1000-8000-00805f9b34fb");
<service android:name=".power.BatteryMonitorService" android:enabled="true"/>
<service android:name=".ble.BluetoothLeService" android:enabled="true"/>
<receiver android:name=".power.PowerConnectedReceiver" android:enabled="true" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>
public class PowerConnectedReceiver extends BroadcastReceiver {
private static final String TAG = "BleNotify.PowerConnectedReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive : " + intent.getAction());
if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
Intent serviceIntent = new Intent(context, BatteryMonitorService.class);
context.startService(serviceIntent);
} else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
Intent serviceIntent = new Intent(context, BatteryMonitorService.class);
context.stopService(serviceIntent);
}
}
}
public class BatteryMonitorService extends Service {
private static final String TAG = "BleNotify.BatteryMonitorService";
private ChargingOnReceiver mChargingOnReceiver;
private boolean isRegisteredChargingReceiver = false;
class ChargingOnReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
float batteryPct = level / (float)scale;
Log.d(TAG, "change battery state : " + batteryPct*100 + "%");
if (batteryPct > 0.9) {
Intent notify = new Intent(BluetoothLeService.ACTION_CALL_BATTERY_NOTIFY);
LocalBroadcastManager.getInstance(context).sendBroadcast(notify);
Log.d(TAG, "send broadcast Notify");
}
}
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
mChargingOnReceiver = new ChargingOnReceiver();
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(mChargingOnReceiver, filter);
isRegisteredChargingReceiver = true;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "starting the BatteryMonitorService.");
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
Log.d(TAG, "terminate the BatteryMonitorService.");
// close process
if (isRegisteredChargingReceiver) {
unregisterReceiver(mChargingOnReceiver);
}
super.onDestroy();
}
}
public class BluetoothLeService extends Service {
private BluetoothGatt mBluetoothGatt;
public final static String ACTION_CALL_BATTERY_NOTIFY =
"com.brilliant.blenotify.ble.le.ACTION_CALL_BATTERY_NOTIFY";
〜中略〜
class GattRequestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive : " + intent.getAction());
if (mBluetoothGatt == null) {
Log.e(TAG, "GattService is not connected...");
return;
}
if (ACTION_CALL_BATTERY_NOTIFY.equals(intent.getAction())) {
BluetoothGattCharacteristic c =
getCharacteristic(GattAttributes.ALERT_SERVICE_UUID,
GattAttributes.ALERT_LEVEL_UUID);
if (c != null) {
// 1 : vibrator
// 2 : sound
int level = 2;
c.setValue(new byte[]{(byte) level});
mBluetoothGatt.writeCharacteristic(c);
}
}
}
}
public BluetoothGattCharacteristic getCharacteristic(UUID sid, UUID cid) {
BluetoothGattService s = mBluetoothGatt.getService(sid);
if (s == null) {
Log.w(TAG, "Service NOT found :" + sid.toString());
return null;
}
BluetoothGattCharacteristic c = s.getCharacteristic(cid);
if (c == null) {
Log.w(TAG, "Characteristic NOT found :" + cid.toString());
return null;
}
return c;
}
このようにすることで、充電中で90パーセントを超えると音を鳴らして通知してくれます。public static final UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180f-0000-1000-8000-00805f9b34fb");
public static final UUID BATTERY_LEVEL_STATE_UUID = UUID.fromString("00002a1b-0000-1000-8000-00805f9b34fb");
BluetoothGattCharacteristic c =
getCharacteristic(GattAttributes.BATTERY_SERVICE_UUID,
GattAttributes.BATTERY_LEVEL_STATE_UUID);
if (c != null) {
final int charaProp = c.getProperties();
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
Log.d(TAG, "has PROPERTY_NOTIFY");
}
mBluetoothGatt.setCharacteristicNotification(c, true);
}
public class BluetoothLeService extends Service {
public final static String ACTION_FINDME_NOTIFY =
"com.brilliant.blenotify.ble.le.ACTION_FINDME_NOTIFY";
〜中略〜
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
UUID uuid = characteristic.getUuid();
Log.e(TAG, "onCharacteristicChanged : " + characteristic.getUuid());
if (GattAttributes.BATTERY_LEVEL_STATE_UUID.equals(uuid)) {
// For all other profiles, writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
Log.d(TAG, "BATTERY_LEVEL_STATE_UUID received : " + new String(data));
if (data != null && data.length > 0) {
// if button pressed.
if (data[0] == 1) {
Intent intent = new Intent(ACTION_FINDME_NOTIFY);
sendBroadcast(intent);
Log.d(TAG, "send broadcast ACTION_FINDME_NOTIFY.");
} else {
Log.d(TAG, "Button is not pressed.");
}
}
} else {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
FindMeRecieverの実装public class FindMeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
long[] pattern = {3000, 1000, 3000, 1000};
vibrator.vibrate(pattern, -1);
}
}
AndrodManifestにも以下を追加しておきます。
<uses-permission android:name="android.permission.VIBRATE"/>
<receiver android:name=".findme.FindMeReceiver" android:enabled="true" android:exported="false"/>
<intent-filter/>
<action android:name="com.brilliant.blenotify.ble.le.ACTION_FINDME_NOTIFY" />
</intent-filter/>
</receiver/>
サービス名
|
UUID
|
説明
|
Generic Access
|
1800
|
デバイス名などの情報取得
|
Immediate Alert
|
1802
|
アラームを鳴らす
|
Link Loss
|
1803
|
接続が切れたときの挙動を設定する
|
Tx Power
|
1804
|
BLEの送信のパワー
|
Battery Service
|
180f
|
バッテリーの状態
|
public static final UUID ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
public static final UUID ALERT_LEVEL_UUID = UUID.fromString("00002a06-0000-1000-8000-00805f9b34fb");
<service android:name=".power.BatteryMonitorService" android:enabled="true"/>
<service android:name=".ble.BluetoothLeService" android:enabled="true"/>
<receiver android:name=".power.PowerConnectedReceiver" android:enabled="true" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>
public class PowerConnectedReceiver extends BroadcastReceiver {
private static final String TAG = "BleNotify.PowerConnectedReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive : " + intent.getAction());
if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
Intent serviceIntent = new Intent(context, BatteryMonitorService.class);
context.startService(serviceIntent);
} else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
Intent serviceIntent = new Intent(context, BatteryMonitorService.class);
context.stopService(serviceIntent);
}
}
}
public class BatteryMonitorService extends Service {
private static final String TAG = "BleNotify.BatteryMonitorService";
private ChargingOnReceiver mChargingOnReceiver;
private boolean isRegisteredChargingReceiver = false;
class ChargingOnReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
float batteryPct = level / (float)scale;
Log.d(TAG, "change battery state : " + batteryPct*100 + "%");
if (batteryPct > 0.9) {
Intent notify = new Intent(BluetoothLeService.ACTION_CALL_BATTERY_NOTIFY);
LocalBroadcastManager.getInstance(context).sendBroadcast(notify);
Log.d(TAG, "send broadcast Notify");
}
}
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
mChargingOnReceiver = new ChargingOnReceiver();
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(mChargingOnReceiver, filter);
isRegisteredChargingReceiver = true;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "starting the BatteryMonitorService.");
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
Log.d(TAG, "terminate the BatteryMonitorService.");
// close process
if (isRegisteredChargingReceiver) {
unregisterReceiver(mChargingOnReceiver);
}
super.onDestroy();
}
}
public class BluetoothLeService extends Service {
private BluetoothGatt mBluetoothGatt;
public final static String ACTION_CALL_BATTERY_NOTIFY =
"com.brilliant.blenotify.ble.le.ACTION_CALL_BATTERY_NOTIFY";
〜中略〜
class GattRequestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive : " + intent.getAction());
if (mBluetoothGatt == null) {
Log.e(TAG, "GattService is not connected...");
return;
}
if (ACTION_CALL_BATTERY_NOTIFY.equals(intent.getAction())) {
BluetoothGattCharacteristic c =
getCharacteristic(GattAttributes.ALERT_SERVICE_UUID,
GattAttributes.ALERT_LEVEL_UUID);
if (c != null) {
// 1 : vibrator
// 2 : sound
int level = 2;
c.setValue(new byte[]{(byte) level});
mBluetoothGatt.writeCharacteristic(c);
}
}
}
}
public BluetoothGattCharacteristic getCharacteristic(UUID sid, UUID cid) {
BluetoothGattService s = mBluetoothGatt.getService(sid);
if (s == null) {
Log.w(TAG, "Service NOT found :" + sid.toString());
return null;
}
BluetoothGattCharacteristic c = s.getCharacteristic(cid);
if (c == null) {
Log.w(TAG, "Characteristic NOT found :" + cid.toString());
return null;
}
return c;
}
このようにすることで、充電中で90パーセントを超えると音を鳴らして通知してくれます。public static final UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180f-0000-1000-8000-00805f9b34fb");
public static final UUID BATTERY_LEVEL_STATE_UUID = UUID.fromString("00002a1b-0000-1000-8000-00805f9b34fb");
BluetoothGattCharacteristic c =
getCharacteristic(GattAttributes.BATTERY_SERVICE_UUID,
GattAttributes.BATTERY_LEVEL_STATE_UUID);
if (c != null) {
final int charaProp = c.getProperties();
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
Log.d(TAG, "has PROPERTY_NOTIFY");
}
mBluetoothGatt.setCharacteristicNotification(c, true);
}
public class BluetoothLeService extends Service {
public final static String ACTION_FINDME_NOTIFY =
"com.brilliant.blenotify.ble.le.ACTION_FINDME_NOTIFY";
〜中略〜
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
UUID uuid = characteristic.getUuid();
Log.e(TAG, "onCharacteristicChanged : " + characteristic.getUuid());
if (GattAttributes.BATTERY_LEVEL_STATE_UUID.equals(uuid)) {
// For all other profiles, writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
Log.d(TAG, "BATTERY_LEVEL_STATE_UUID received : " + new String(data));
if (data != null && data.length > 0) {
// if button pressed.
if (data[0] == 1) {
Intent intent = new Intent(ACTION_FINDME_NOTIFY);
sendBroadcast(intent);
Log.d(TAG, "send broadcast ACTION_FINDME_NOTIFY.");
} else {
Log.d(TAG, "Button is not pressed.");
}
}
} else {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
FindMeRecieverの実装public class FindMeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
long[] pattern = {3000, 1000, 3000, 1000};
vibrator.vibrate(pattern, -1);
}
}
AndrodManifestにも以下を追加しておきます。
<uses-permission android:name="android.permission.VIBRATE"/>
<receiver android:name=".findme.FindMeReceiver" android:enabled="true" android:exported="false"/>
<intent-filter/>
<action android:name="com.brilliant.blenotify.ble.le.ACTION_FINDME_NOTIFY" />
</intent-filter/>
</receiver/>
https://linkingiot.com/developer/#developers より引用はじめに
https://linkingiot.com/developer/#developers より引用はじめに
BluetoothManager mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager != null) {
BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
}
次にGATT Serverのインスタンスを取得します。(BluetoothManager#openGattServer)mGattServer = mBluetoothManager.openGattServer(this, new BLEServer());
class BLEServer extends BluetoothGattServerCallback {
//セントラルから読み込み要求が来ると呼ばれる
public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice device, int requestId,
int offset, BluetoothGattCharacteristic characteristic) {
}
//セントラルから書き込み要求が来ると呼ばれる
public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device, int requestId,
BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded,
int offset, byte[] value) {
}
}
private void setServices() {
//serviceUUIDを設定BluetoothGattService service = new BluetoothGattService(
UUID.fromString(Constants.SERVICE_UUID),
BluetoothGattService.SERVICE_TYPE_PRIMARY);
//characteristicUUIDを設定
BluetoothGattCharacteristic charRead = new BluetoothGattCharacteristic(
UUID.fromString(Constants.CHAR_READ_UUID),
BluetoothGattCharacteristic.PROPERTY_READ,
BluetoothGattCharacteristic.PERMISSION_READ);
BluetoothGattCharacteristic charWrite = new BluetoothGattCharacteristic(
UUID.fromString(Constants.CHAR_WRITE_UUID),
BluetoothGattCharacteristic.PROPERTY_WRITE,
BluetoothGattCharacteristic.PERMISSION_WRITE);
//characteristicUUIDをserviceUUIDにのせる
service.addCharacteristic(charRead);
service.addCharacteristic(charWrite);
//serviceUUIDをサーバーにのせる
mGattServer.addService(service);
}
次にアドバタイジング時の設定(AdvertiseSettings)とデータ(AdvertiseData)の設定を行います。//AdvertiseSettingsの設定
private AdvertiseSettings buildAdvertiseSettings() {
AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER);
settingsBuilder.setTimeout(0);
return settingsBuilder.build();
}
//AdvertiseDataの設定
private AdvertiseData buildAdvertiseData() {
AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
dataBuilder.addServiceUuid(ParcelUuid.fromString(Constants.SERVICE_UUID));
dataBuilder.setIncludeDeviceName(true);
return dataBuilder.build();
}
//Advertiseの開始
private void startAdvertising() {
setServices();
AdvertiseSettings settings = buildAdvertiseSettings();
AdvertiseData data = buildAdvertiseData();
mAdvertiseCallback = new SimpleAdvertiseCallback();
mBluetoothLeAdvertiser.startAdvertising(settings, data,mAdvertiseCallback);
}
//Advertiseの成功可否
private class SimpleAdvertiseCallback extends AdvertiseCallback {
@Override
public void onStartFailure(int errorCode) {
super.onStartFailure(errorCode);
Log.d(TAG, "Advertising failed");
}
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
Log.d(TAG, "Advertising successfully started");
}
}
private void stopAdvertising() {
Log.d(TAG, "Service: Stopping Advertising");
if (mGattServer != null) {
mGattServer.clearServices();
mGattServer.close();
mGattServer = null;
}
if (mBluetoothLeAdvertiser != null) {
mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
mAdvertiseCallback = null;
}
}
以上で、Nexus 9がペリフェラルとして機能するようになります。public void readCharacteristic() {
BluetoothGattCharacteristic read = mBluetoothLeService.getCharacteristic(
GattAttributes.SERVICE_UUID,
GattAttributes.CHAR_READ_UUID);
mBluetoothGatt.readCharacteristic(read);
}
public BluetoothGattCharacteristic getCharacteristic(String sid, String cid) {
BluetoothGattService s = mBluetoothGatt.getService(UUID.fromString(sid));
if (s == null) {
Log.w(TAG, "Service NoT found :" + sid);
return null;
}
BluetoothGattCharacteristic c = s.getCharacteristic(UUID.fromString(cid));
if (c == null) {
Log.w(TAG, "Characteristic NOT found :" + cid);
return null;
}
return c;
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
final byte[] data = characteristic.getValue();
Log.d(TAG, "onCharacteristicRead : " + new String(data));
}
//セントラルからReadRequestが来ると呼ばれる
public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice device, int requestId,
int offset, BluetoothGattCharacteristic characteristic) {
//セントラルに任意の文字を返信する
if (UUID.fromString(Constants. CHAR_READ_UUID).equals(characteristic.getUuid())) {
String response = "your message.";
byte value[] = response.getBytes();
mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
}
}
public void writeCharacteristic() {
BluetoothGattCharacteristic write = getCharacteristic(
UUID.fromString(GattAttributes.SERVICE_UUID),
UUID.fromString(GattAttributes.CHAR_WRITE_UUID));
String message = "your message";
write.setValue(message);
mBluetoothGatt.writeCharacteristic(characteristic);
}
public BluetoothGattCharacteristic getCharacteristic(String sid, String cid) {
BluetoothGattService s = mBluetoothGatt.getService(UUID.fromString(sid));
if (s == null) {
Log.w(TAG, "Service NoT found :" + sid);
return null;
}
BluetoothGattCharacteristic c = s.getCharacteristic(UUID.fromString(cid));
if (c == null) {
Log.w(TAG, "Characteristic NOT found :" + cid);
return null;
}
return c;
}
//セントラルから書き込み要求が来ると呼ばれる
public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device, int requestId,
BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded,
int offset, byte[] value) {
Log.d(TAG, "onCharacteristicWriteRequest");
if (UUID.fromString(Constants.CHAR_WRITE_UUID).equals(characteristic.getUuid())) {
final byte[] data = characteristic.getValue();
Log.d(TAG, "onCharacteristicRead : " + new String(data));
mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null);
}
}
BluetoothManager mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager != null) {
BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
}
次にGATT Serverのインスタンスを取得します。(BluetoothManager#openGattServer)mGattServer = mBluetoothManager.openGattServer(this, new BLEServer());
class BLEServer extends BluetoothGattServerCallback {
//セントラルから読み込み要求が来ると呼ばれる
public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice device, int requestId,
int offset, BluetoothGattCharacteristic characteristic) {
}
//セントラルから書き込み要求が来ると呼ばれる
public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device, int requestId,
BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded,
int offset, byte[] value) {
}
}
private void setServices() {
//serviceUUIDを設定BluetoothGattService service = new BluetoothGattService(
UUID.fromString(Constants.SERVICE_UUID),
BluetoothGattService.SERVICE_TYPE_PRIMARY);
//characteristicUUIDを設定
BluetoothGattCharacteristic charRead = new BluetoothGattCharacteristic(
UUID.fromString(Constants.CHAR_READ_UUID),
BluetoothGattCharacteristic.PROPERTY_READ,
BluetoothGattCharacteristic.PERMISSION_READ);
BluetoothGattCharacteristic charWrite = new BluetoothGattCharacteristic(
UUID.fromString(Constants.CHAR_WRITE_UUID),
BluetoothGattCharacteristic.PROPERTY_WRITE,
BluetoothGattCharacteristic.PERMISSION_WRITE);
//characteristicUUIDをserviceUUIDにのせる
service.addCharacteristic(charRead);
service.addCharacteristic(charWrite);
//serviceUUIDをサーバーにのせる
mGattServer.addService(service);
}
次にアドバタイジング時の設定(AdvertiseSettings)とデータ(AdvertiseData)の設定を行います。//AdvertiseSettingsの設定
private AdvertiseSettings buildAdvertiseSettings() {
AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER);
settingsBuilder.setTimeout(0);
return settingsBuilder.build();
}
//AdvertiseDataの設定
private AdvertiseData buildAdvertiseData() {
AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
dataBuilder.addServiceUuid(ParcelUuid.fromString(Constants.SERVICE_UUID));
dataBuilder.setIncludeDeviceName(true);
return dataBuilder.build();
}
//Advertiseの開始
private void startAdvertising() {
setServices();
AdvertiseSettings settings = buildAdvertiseSettings();
AdvertiseData data = buildAdvertiseData();
mAdvertiseCallback = new SimpleAdvertiseCallback();
mBluetoothLeAdvertiser.startAdvertising(settings, data,mAdvertiseCallback);
}
//Advertiseの成功可否
private class SimpleAdvertiseCallback extends AdvertiseCallback {
@Override
public void onStartFailure(int errorCode) {
super.onStartFailure(errorCode);
Log.d(TAG, "Advertising failed");
}
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
Log.d(TAG, "Advertising successfully started");
}
}
private void stopAdvertising() {
Log.d(TAG, "Service: Stopping Advertising");
if (mGattServer != null) {
mGattServer.clearServices();
mGattServer.close();
mGattServer = null;
}
if (mBluetoothLeAdvertiser != null) {
mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
mAdvertiseCallback = null;
}
}
以上で、Nexus 9がペリフェラルとして機能するようになります。public void readCharacteristic() {
BluetoothGattCharacteristic read = mBluetoothLeService.getCharacteristic(
GattAttributes.SERVICE_UUID,
GattAttributes.CHAR_READ_UUID);
mBluetoothGatt.readCharacteristic(read);
}
public BluetoothGattCharacteristic getCharacteristic(String sid, String cid) {
BluetoothGattService s = mBluetoothGatt.getService(UUID.fromString(sid));
if (s == null) {
Log.w(TAG, "Service NoT found :" + sid);
return null;
}
BluetoothGattCharacteristic c = s.getCharacteristic(UUID.fromString(cid));
if (c == null) {
Log.w(TAG, "Characteristic NOT found :" + cid);
return null;
}
return c;
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
final byte[] data = characteristic.getValue();
Log.d(TAG, "onCharacteristicRead : " + new String(data));
}
//セントラルからReadRequestが来ると呼ばれる
public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice device, int requestId,
int offset, BluetoothGattCharacteristic characteristic) {
//セントラルに任意の文字を返信する
if (UUID.fromString(Constants. CHAR_READ_UUID).equals(characteristic.getUuid())) {
String response = "your message.";
byte value[] = response.getBytes();
mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
}
}
public void writeCharacteristic() {
BluetoothGattCharacteristic write = getCharacteristic(
UUID.fromString(GattAttributes.SERVICE_UUID),
UUID.fromString(GattAttributes.CHAR_WRITE_UUID));
String message = "your message";
write.setValue(message);
mBluetoothGatt.writeCharacteristic(characteristic);
}
public BluetoothGattCharacteristic getCharacteristic(String sid, String cid) {
BluetoothGattService s = mBluetoothGatt.getService(UUID.fromString(sid));
if (s == null) {
Log.w(TAG, "Service NoT found :" + sid);
return null;
}
BluetoothGattCharacteristic c = s.getCharacteristic(UUID.fromString(cid));
if (c == null) {
Log.w(TAG, "Characteristic NOT found :" + cid);
return null;
}
return c;
}
//セントラルから書き込み要求が来ると呼ばれる
public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device, int requestId,
BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded,
int offset, byte[] value) {
Log.d(TAG, "onCharacteristicWriteRequest");
if (UUID.fromString(Constants.CHAR_WRITE_UUID).equals(characteristic.getUuid())) {
final byte[] data = characteristic.getValue();
Log.d(TAG, "onCharacteristicRead : " + new String(data));
mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null);
}
}
<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>※端末がBLEに対応しているかの確認
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "BLE未対応端末です", Toast.LENGTH_SHORT).show();
finish();
}
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> または <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>しかし、それだけではBLE機能を使用することは出来ません。。
private boolean checkPermission() {
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_LOCATION_STATE);
return false;
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (PERMISSIONS_REQUEST_LOCATION_STATE == requestCode) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 許可された場合
Toast.makeText(this, "許可されました", Toast.LENGTH_SHORT).show();
} else {
// 不許可だった場合
Toast.makeText(this, "権限を拒否されました", Toast.LENGTH_SHORT).show();
finish();
}
}
}
final BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter();次に、端末のBluetoothが有効になっているかの確認を行います。
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
// Device scan callback.
private ScanCallback mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, final ScanResult result) {
super.onScanResult(callbackType, result);
if (result != null && result.getDevice() != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mLeDeviceListAdapter.addDevice(result.getDevice());
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
}
};
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);接続が確立されると、BluetoothGattCallback#onConnectionStateChangeが呼ばれます。
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
mBluetoothGatt.discoverServices();
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
serviceList = gatt.getServices();
// サービスの内容を取得等処理を行う
// 取得したサービスからBLEデバイスの情報を取得する
}
<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>※端末がBLEに対応しているかの確認
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "BLE未対応端末です", Toast.LENGTH_SHORT).show();
finish();
}
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> または <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>しかし、それだけではBLE機能を使用することは出来ません。。
private boolean checkPermission() {
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_LOCATION_STATE);
return false;
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (PERMISSIONS_REQUEST_LOCATION_STATE == requestCode) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 許可された場合
Toast.makeText(this, "許可されました", Toast.LENGTH_SHORT).show();
} else {
// 不許可だった場合
Toast.makeText(this, "権限を拒否されました", Toast.LENGTH_SHORT).show();
finish();
}
}
}
final BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter();次に、端末のBluetoothが有効になっているかの確認を行います。
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
// Device scan callback.
private ScanCallback mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, final ScanResult result) {
super.onScanResult(callbackType, result);
if (result != null && result.getDevice() != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mLeDeviceListAdapter.addDevice(result.getDevice());
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
}
};
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);接続が確立されると、BluetoothGattCallback#onConnectionStateChangeが呼ばれます。
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
mBluetoothGatt.discoverServices();
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
serviceList = gatt.getServices();
// サービスの内容を取得等処理を行う
// 取得したサービスからBLEデバイスの情報を取得する
}
>ruby -v ruby 2.1.7p400 (2015-08-18 revision 51632) [x64-mingw32]
>gem install appium_lib
# encoding: utf-8
require "appium_lib"
desired_caps = {
caps: {
platformName: "Android",
deviceName: "Android Device",
app: "#{Dir.pwd}/selendroid-test-app.apk",
}
}
driver = Appium::Driver.new(desired_caps).start_driver
Appium.promote_appium_methods Object
button_element = find_element(:id, "io.selendroid.testapp:id/visibleButtonTest")
button_element.click
sleep 3
text_element = find_element(:id, "io.selendroid.testapp:id/visibleTextView")
displayed_text = text_element.text
button_element.click
sleep 3
puts displayed_text
driver.quit
>ruby sample.rb
>ruby -v ruby 2.1.7p400 (2015-08-18 revision 51632) [x64-mingw32]
>gem install appium_lib
# encoding: utf-8
require "appium_lib"
desired_caps = {
caps: {
platformName: "Android",
deviceName: "Android Device",
app: "#{Dir.pwd}/selendroid-test-app.apk",
}
}
driver = Appium::Driver.new(desired_caps).start_driver
Appium.promote_appium_methods Object
button_element = find_element(:id, "io.selendroid.testapp:id/visibleButtonTest")
button_element.click
sleep 3
text_element = find_element(:id, "io.selendroid.testapp:id/visibleTextView")
displayed_text = text_element.text
button_element.click
sleep 3
puts displayed_text
driver.quit
>ruby sample.rb
| HID(Human Interface Device Profile) | 入力機器を扱うためのプロファイル |
| HSP(Headset Profile) | ヘッドセットと通信するためのプロファイル |
| HFP(Hands-Free Profile) | ハンズフリー通話をするためのプロファイル |
| A2DP(Advanced Audio Distribution Profile) | 高音質のステレオ音声を伝送するためのプロファイル |
| AVRCP(Audio/Video Remote Control Profile) | AV機器のコントロール(再生、早送り等)を行うためのプロファル |
| FTP(File Transfer Profile) | ファイル転送プロファイル |
| ANP(Alert Notification Profile) | 電話やメールなどの着信を通知するプロファイル |
| BLP(Blood Pressure Profile) | 血圧計から血圧情報を伝送するためのプロファイル |
| CPP(Cycling Power Profile) | サイクリング時の力などを情報を伝送するためのプロファイル |
| CSCP(Cycling Speed and Cadence Profile) | サイクリング時のスピードや回転数などの情報を伝送するためのプロファイル |
| FMP(Find Me Profile) | 遠隔からアラームやバイブレーションを鳴動させ、装置の場所を調べるためのプロファイル |
| GLP(Glucose Profile) | 血糖値の情報を伝送するためのプロファイル |
| HOGP(HID over GATT Profile) | マウスやキーボードなどを接続するためのプロファイル |
| HTP(Health Thermometer Profile) | 体温計の情報を伝送するためのプロファイル |
| HRP(Heart Rate Profile) | 心拍計の情報を伝送するためのプロファイル |
| IPSP (Internet Protocol Support Profile) | IPv6/6LoWPAN経由でインターネットに接続するプロファイル |
| PASP(Phone Alert Status Profile) | 電話着信時の鳴動などを他の機器から止めるためのプロファイル |
| PXP(Proximity Profile) | 互いの機器間の距離をモニタリングするためのプロファイル |
| RSCP(Running Speed and Cadence Profile) | ランニング時のスピードや歩幅などの情報を伝送するためのプロファイル |
| ScPP(Scan Parameters Profile) | 装置のスキャンをするためのプロファイル |
| TIP(Time Profile) | 時刻情報を通知するためのプロフィール |
| HID(Human Interface Device Profile) | 入力機器を扱うためのプロファイル |
| HSP(Headset Profile) | ヘッドセットと通信するためのプロファイル |
| HFP(Hands-Free Profile) | ハンズフリー通話をするためのプロファイル |
| A2DP(Advanced Audio Distribution Profile) | 高音質のステレオ音声を伝送するためのプロファイル |
| AVRCP(Audio/Video Remote Control Profile) | AV機器のコントロール(再生、早送り等)を行うためのプロファル |
| FTP(File Transfer Profile) | ファイル転送プロファイル |
| ANP(Alert Notification Profile) | 電話やメールなどの着信を通知するプロファイル |
| BLP(Blood Pressure Profile) | 血圧計から血圧情報を伝送するためのプロファイル |
| CPP(Cycling Power Profile) | サイクリング時の力などを情報を伝送するためのプロファイル |
| CSCP(Cycling Speed and Cadence Profile) | サイクリング時のスピードや回転数などの情報を伝送するためのプロファイル |
| FMP(Find Me Profile) | 遠隔からアラームやバイブレーションを鳴動させ、装置の場所を調べるためのプロファイル |
| GLP(Glucose Profile) | 血糖値の情報を伝送するためのプロファイル |
| HOGP(HID over GATT Profile) | マウスやキーボードなどを接続するためのプロファイル |
| HTP(Health Thermometer Profile) | 体温計の情報を伝送するためのプロファイル |
| HRP(Heart Rate Profile) | 心拍計の情報を伝送するためのプロファイル |
| IPSP (Internet Protocol Support Profile) | IPv6/6LoWPAN経由でインターネットに接続するプロファイル |
| PASP(Phone Alert Status Profile) | 電話着信時の鳴動などを他の機器から止めるためのプロファイル |
| PXP(Proximity Profile) | 互いの機器間の距離をモニタリングするためのプロファイル |
| RSCP(Running Speed and Cadence Profile) | ランニング時のスピードや歩幅などの情報を伝送するためのプロファイル |
| ScPP(Scan Parameters Profile) | 装置のスキャンをするためのプロファイル |
| TIP(Time Profile) | 時刻情報を通知するためのプロフィール |
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.raw" />
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(cameraId);
// We only use a camera that supports RAW in this sample.
if (!contains(characteristics.get(
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES),
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
continue;
}
if (mRawImageReader == null || mRawImageReader.getAndRetain() == null) {
mRawImageReader = new RefCountedAutoCloseable<>(<
ImageReader.newInstance(largestRaw.getWidth(),
largestRaw.getHeight(), ImageFormat.RAW_SENSOR, /*maxImages*/ 5));
}
mRawImageReader.get().setOnImageAvailableListener(
mOnRawImageAvailableListener, mBackgroundHandler);
}
private void openCamera() {
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
manager.openCamera(cameraId, mStateCallback, backgroundHandler);
}
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice cameraDevice) {
synchronized (mCameraStateLock) {
// Start the preview session if the TextureView has been set up already.
if (mPreviewSize != null && mTextureView.isAvailable()) {
createCameraPreviewSessionLocked();
}
}
}
private void createCameraPreviewSessionLocked() {
try {
SurfaceTexture texture = mTextureView.getSurfaceTexture();
// Here, we create a CameraCaptureSession for camera preview.
mCameraDevice.createCaptureSession(Arrays.asList(surface,
mJpegImageReader.get().getSurface(),
mRawImageReader.get().getSurface()), new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
synchronized (mCameraStateLock) {
setup3AControlsLocked(mPreviewRequestBuilder);
// Finally, we start displaying the camera preview.
cameraCaptureSession.setRepeatingRequest(
mPreviewRequestBuilder.build(),
mPreCaptureCallback, mBackgroundHandler);
mState = STATE_PREVIEW;
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void takePicture() {
// Replace the existing repeating request with one with updated 3A triggers.
mCaptureSession.capture(mPreviewRequestBuilder.build(), mPreCaptureCallback,
mBackgroundHandler);
}
private void captureStillPictureLocked() {
// Use the same AE and AF modes as the preview.
setup3AControlsLocked(captureBuilder);
// Create an ImageSaverBuilder in which to collect results, and add it to the queue
// of active requests.
ImageSaver.ImageSaverBuilder rawBuilder = new ImageSaver.ImageSaverBuilder(activity)
.setCharacteristics(mCharacteristics);
mRawResultQueue.put((int) request.getTag(), rawBuilder);
mCaptureSession.capture(request, mCaptureCallback, mBackgroundHandler);
}
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
TotalCaptureResult result) {
synchronized (mCameraStateLock) {
rawBuilder = mRawResultQueue.get(requestId);
handleCompletionLocked(requestId, rawBuilder, mRawResultQueue);
if (rawBuilder != null) {
rawBuilder.setResult(result);
if (jpegBuilder != null) sb.append(", ");
sb.append("Saving RAW as: ");
sb.append(rawBuilder.getSaveLocation());
}
finishedCaptureLocked();
}
}
private void handleCompletionLocked(int requestId, ImageSaver.ImageSaverBuilder builder,
TreeMap<Integer, ImageSaver.ImageSaverBuilder> queue) {
ImageSaver saver = builder.buildIfComplete();
if (saver != null) {
queue.remove(requestId);
AsyncTask.THREAD_POOL_EXECUTOR.execute(saver);
}
}
switch (format) {
case ImageFormat.RAW_SENSOR: {
DngCreator dngCreator = new DngCreator(mCharacteristics, mCaptureResult);
FileOutputStream output = null;
try {
output = new FileOutputStream(mFile);
dngCreator.writeImage(output, mImage);
success = true;
} finally {
mImage.close();
closeOutput(output);
}
}
}
if (success) {
MediaScannerConnection.scanFile(mContext, new String[]{mFile.getPath()},
/*mimeTypes*/null, new MediaScannerConnection.MediaScannerConnectionClient() {
@Override
public void onScanCompleted(String path, Uri uri) {
Log.i(TAG, "Scanned " + path + ":");
Log.i(TAG, "-> uri=" + uri);
}
});
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.raw" />
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(cameraId);
// We only use a camera that supports RAW in this sample.
if (!contains(characteristics.get(
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES),
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
continue;
}
if (mRawImageReader == null || mRawImageReader.getAndRetain() == null) {
mRawImageReader = new RefCountedAutoCloseable<>(<
ImageReader.newInstance(largestRaw.getWidth(),
largestRaw.getHeight(), ImageFormat.RAW_SENSOR, /*maxImages*/ 5));
}
mRawImageReader.get().setOnImageAvailableListener(
mOnRawImageAvailableListener, mBackgroundHandler);
}
private void openCamera() {
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
manager.openCamera(cameraId, mStateCallback, backgroundHandler);
}
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice cameraDevice) {
synchronized (mCameraStateLock) {
// Start the preview session if the TextureView has been set up already.
if (mPreviewSize != null && mTextureView.isAvailable()) {
createCameraPreviewSessionLocked();
}
}
}
private void createCameraPreviewSessionLocked() {
try {
SurfaceTexture texture = mTextureView.getSurfaceTexture();
// Here, we create a CameraCaptureSession for camera preview.
mCameraDevice.createCaptureSession(Arrays.asList(surface,
mJpegImageReader.get().getSurface(),
mRawImageReader.get().getSurface()), new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
synchronized (mCameraStateLock) {
setup3AControlsLocked(mPreviewRequestBuilder);
// Finally, we start displaying the camera preview.
cameraCaptureSession.setRepeatingRequest(
mPreviewRequestBuilder.build(),
mPreCaptureCallback, mBackgroundHandler);
mState = STATE_PREVIEW;
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void takePicture() {
// Replace the existing repeating request with one with updated 3A triggers.
mCaptureSession.capture(mPreviewRequestBuilder.build(), mPreCaptureCallback,
mBackgroundHandler);
}
private void captureStillPictureLocked() {
// Use the same AE and AF modes as the preview.
setup3AControlsLocked(captureBuilder);
// Create an ImageSaverBuilder in which to collect results, and add it to the queue
// of active requests.
ImageSaver.ImageSaverBuilder rawBuilder = new ImageSaver.ImageSaverBuilder(activity)
.setCharacteristics(mCharacteristics);
mRawResultQueue.put((int) request.getTag(), rawBuilder);
mCaptureSession.capture(request, mCaptureCallback, mBackgroundHandler);
}
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
TotalCaptureResult result) {
synchronized (mCameraStateLock) {
rawBuilder = mRawResultQueue.get(requestId);
handleCompletionLocked(requestId, rawBuilder, mRawResultQueue);
if (rawBuilder != null) {
rawBuilder.setResult(result);
if (jpegBuilder != null) sb.append(", ");
sb.append("Saving RAW as: ");
sb.append(rawBuilder.getSaveLocation());
}
finishedCaptureLocked();
}
}
private void handleCompletionLocked(int requestId, ImageSaver.ImageSaverBuilder builder,
TreeMap<Integer, ImageSaver.ImageSaverBuilder> queue) {
ImageSaver saver = builder.buildIfComplete();
if (saver != null) {
queue.remove(requestId);
AsyncTask.THREAD_POOL_EXECUTOR.execute(saver);
}
}
switch (format) {
case ImageFormat.RAW_SENSOR: {
DngCreator dngCreator = new DngCreator(mCharacteristics, mCaptureResult);
FileOutputStream output = null;
try {
output = new FileOutputStream(mFile);
dngCreator.writeImage(output, mImage);
success = true;
} finally {
mImage.close();
closeOutput(output);
}
}
}
if (success) {
MediaScannerConnection.scanFile(mContext, new String[]{mFile.getPath()},
/*mimeTypes*/null, new MediaScannerConnection.MediaScannerConnectionClient() {
@Override
public void onScanCompleted(String path, Uri uri) {
Log.i(TAG, "Scanned " + path + ":");
Log.i(TAG, "-> uri=" + uri);
}
});
Android KitKat Hacks プロが教えるテクニック & ツール
株式会社ブリリアントサービス 著
NFC Hacks プロが教えるテクニック&ツール
株式会社ブリリアントサービス 著
Androidプログラミングの教科書
藤田 竜史、要 徳幸、住友 孝郎、日高 正博、小林 慎治、木村 尭海 著
入門Androidアプリケーションテスト
瀬戸 直喜/株式会社ブリリアントサービス 著
実践スマートフォンアプリケーション開発
株式会社ブリリアントサービス、八木 俊広、原 昇平、かわかみ ひろき 著
ジオモバイルプログラミング
郷田まり子/宅間俊志/近藤昭雄 著
ANDROID HACKS プロが教えるテクニック&ツール
株式会社ブリリアントサービス 著