はじめに
GitHubから取得したコード(Advertiseのみ)に追記して(Scan)、
AdvertiseとScanを同時に実現
切り替える必要はない
環境
Zenfone2laser(Android 5.0.2)で動作確認済み
AdvertiseとScanを同時に行えることを実証
Nexus5(受信用、送信不可)
Zenfone2 laser(送受信用)
確認方法
送信の確認
Zenfone2 laserでNexus5に送信
受信の確認
Aplix BeaconでNexus5,Zenfon2 laserに送信
reference
メイン機能は以下で取得
・https://github.com/youten/aBeacon
スキャン機能の追加
・http://www.gaprot.jp/pickup/ibeacon/abeacon/
MainActivity.java
/*
* Copyright (C) 2014 youten
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package youten.redo.ble.abeacon;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.content.Intent;
import android.os.Bundle;
import android.os.ParcelUuid;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.util.UUID;
import youten.redo.ble.util.BleUtil;
public class MainActivity extends Activity {
private static final String TAG = "aBeacon";
private static final int REQUEST_ENABLE_BT = 1;
// BT
private BluetoothAdapter mBTAdapter;
private BluetoothLeAdvertiser mBTAdvertiser;
private BluetoothGattServer mGattServer;
// View
private Button mIBeaconButton;
private Button mIBeaconScanButton;
private Button mIASButton;
private Button mStopButton;
private Button mStopScanButton;
private TextView tv;
private long count=0;
private AdvertiseCallback mAdvCallback = new AdvertiseCallback() {
@Override
public void onStartSuccess(android.bluetooth.le.AdvertiseSettings settingsInEffect) {
// Advする際に設定した値と実際に動作させることに成功したSettingsが違うとsettingsInEffectに
// 有効な値が格納される模様です。設定通りに動かすことに成功した際にはnullが返る模様。
if (settingsInEffect != null) {
Log.d(TAG, "onStartSuccess TxPowerLv="
+ settingsInEffect.getTxPowerLevel()
+ " mode=" + settingsInEffect.getMode()
+ " timeout=" + settingsInEffect.getTimeout());
} else {
Log.d(TAG, "onStartSuccess, settingInEffect is null");
}
mIBeaconButton.setEnabled(false);
mIASButton.setEnabled(false);
mIBeaconScanButton.setEnabled(true); // addition for scan
mStopButton.setEnabled(true);
mStopScanButton.setEnabled(false); // addition for scan
setProgressBarIndeterminateVisibility(false);
}
@Override
public void onStartFailure(int errorCode) {
Log.d(TAG, "onStartFailure errorCode=" + errorCode);
};
};
private BluetoothAdapter.LeScanCallback mLeScanCallback=new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
ParcelUuid[] uuids = device.getUuids();
String uuid = "";
if (uuids != null) {
for (ParcelUuid puuid : uuids) {
uuid += puuid.toString() + " ";
}
} else {
Log.d(TAG, "uuid null");
}
String msg = "name=" + device.getName() + ", bondStatus=" + device.getBondState()
+ ", address=" + device.getAddress() + ", type=" + device.getType() + ", uuids=" + uuid;
Log.d("BLEActivity", msg);
//scanrecord to uuid
if (scanRecord.length > 30) {
if ((scanRecord[5] == (byte) 0x4c) && (scanRecord[6] == (byte) 0x00) && (scanRecord[7] == (byte) 0x02) && (scanRecord[8] == (byte) 0x15)) {
String uuid2 = IntToHex2(scanRecord[9] & 0xff) + IntToHex2(scanRecord[10] & 0xff) + IntToHex2(scanRecord[11] & 0xff) + IntToHex2(scanRecord[12] & 0xff)
+ "-" + IntToHex2(scanRecord[13] & 0xff) + IntToHex2(scanRecord[14] & 0xff)
+ "-" + IntToHex2(scanRecord[15] & 0xff) + IntToHex2(scanRecord[16] & 0xff)
+ "-" + IntToHex2(scanRecord[17] & 0xff) + IntToHex2(scanRecord[18] & 0xff)
+ "-" + IntToHex2(scanRecord[19] & 0xff) + IntToHex2(scanRecord[20] & 0xff) + IntToHex2(scanRecord[21] & 0xff) + IntToHex2(scanRecord[22] & 0xff) + IntToHex2(scanRecord[23] & 0xff) + IntToHex2(scanRecord[24] & 0xff);
String major2 = IntToHex2(scanRecord[25] & 0xff) + IntToHex2(scanRecord[26] & 0xff);
String minor2 = IntToHex2(scanRecord[27] & 0xff) + IntToHex2(scanRecord[28] & 0xff);
String uuid_text="["+(count++)+"] uuid:" + uuid2 + ",major:" + major2 + ",minor:" + minor2;
Log.d(TAG, uuid_text);
tv.setText(uuid_text);
}
}
}
public String IntToHex2(int i) {
char hex_2[] = {Character.forDigit((i >> 4) & 0x0f, 16), Character.forDigit(i & 0x0f, 16)};
String hex_2_str = new String(hex_2);
return hex_2_str.toUpperCase();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG,"onCreate");
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_main);
init();
}
@Override
protected void onStop() {
Log.d(TAG,"onStop");
super.onStop();
stopAdvertise();
}
private void init() {
Log.d(TAG,"init");
tv=(TextView)findViewById(R.id.textview);
// BLE check
if (!BleUtil.isBLESupported(this)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}
// BT check
BluetoothManager manager = BleUtil.getManager(this);
if (manager != null) {
mBTAdapter = manager.getAdapter();
}
if ((mBTAdapter == null) || (!mBTAdapter.isEnabled())) {
Toast.makeText(this, R.string.bt_unavailable, Toast.LENGTH_SHORT).show();
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
mIBeaconButton = (Button) findViewById(R.id.ibeacon_button);
mIBeaconButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startIBeaconAdvertise();
}
});
// addition for scan
mIBeaconScanButton = (Button) findViewById(R.id.ibeacon_scan_button);
mIBeaconScanButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startIBeaconScan();
}
});
mIASButton = (Button) findViewById(R.id.ias_button);
mIASButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startIASAdvertise();
}
});
mStopButton = (Button) findViewById(R.id.stop_button);
mStopButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
stopAdvertise();
}
});
// addition for scan
mStopScanButton = (Button) findViewById(R.id.stop_scan_button);
mStopScanButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
stopScan();
}
});
}
// start Advertise as iBeacon
private void startIBeaconAdvertise() {
if (mBTAdapter == null) {
return;
}
if (mBTAdvertiser == null) {
mBTAdvertiser = mBTAdapter.getBluetoothLeAdvertiser();
}
if (mBTAdvertiser != null) {
mBTAdvertiser.startAdvertising(
BleUtil.createAdvSettings(true, 0),
BleUtil.createIBeaconAdvertiseData(
UUID.fromString("01020304-0506-0708-1112-131415161718"),
(short) 257, (short) 514, (byte) 0xc5),
mAdvCallback);
}
startIBeaconScan();
}
// addition for scan
private void startIBeaconScan(){
//stopAdvertise();
mBTAdapter.startLeScan(mLeScanCallback);
mIBeaconButton.setEnabled(true);
mIBeaconScanButton.setEnabled(true);
mIASButton.setEnabled(false);
mStopButton.setEnabled(false);
mStopScanButton.setEnabled(true); // addition for scan
}
// addition for scan
private void stopScan(){
mBTAdapter.stopLeScan(mLeScanCallback);
tv.setText("");
mIBeaconButton.setEnabled(true);
mIASButton.setEnabled(true);
mIBeaconScanButton.setEnabled(true); // addition for scan
mStopButton.setEnabled(false);
mStopScanButton.setEnabled(false); // addition for scan
setProgressBarIndeterminateVisibility(false);
}
// start Advertise as Immediate Alert Service
private void startIASAdvertise() {
if (mBTAdapter == null) {
return;
}
if (mBTAdvertiser == null) {
mBTAdvertiser = mBTAdapter.getBluetoothLeAdvertiser();
}
if (mBTAdvertiser != null) {
ImmediateAlertService ias = new ImmediateAlertService();
mGattServer = BleUtil.getManager(this).openGattServer(this, ias);
ias.setupServices(mGattServer);
mBTAdvertiser.startAdvertising(
BleUtil.createAdvSettings(true, 0),
BleUtil.createFMPAdvertiseData(),
mAdvCallback);
}
}
private void stopAdvertise() {
if (mGattServer != null) {
mGattServer.clearServices();
mGattServer.close();
mGattServer = null;
}
if (mBTAdvertiser != null) {
mBTAdvertiser.stopAdvertising(mAdvCallback);
mBTAdvertiser = null;
}
mIBeaconButton.setEnabled(true);
mIASButton.setEnabled(true);
mIBeaconScanButton.setEnabled(true); // addition for scan
mStopButton.setEnabled(false);
mStopScanButton.setEnabled(false); // addition for scan
setProgressBarIndeterminateVisibility(false);
// addtion
stopScan();
}
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:orientation="vertical"
tools:context="${relativePackage}.${activityClass}" >
<Button
android:id="@+id/ibeacon_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/label_ibeacon_button" />
<Button
android:id="@+id/ibeacon_scan_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="start scan" />
<Button
android:id="@+id/ias_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/label_ias_button" />
<Button
android:id="@+id/stop_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false"
android:text="@string/label_stop_button" />
<Button
android:id="@+id/stop_scan_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false"
android:text="stop scan" />
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="scan id"/>
</LinearLayout>