LoginSignup
6
6

More than 5 years have passed since last update.

BLEのAdvertiseとScanを同時に行う

Last updated at Posted at 2015-09-17

はじめに

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>
6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6