Android基于蓝牙iBeacon的室内定位App和算法

一、简介

室内部署蓝牙信标,移动端app通过接收广播信号,

通过定位算法实现位置定位,并在三维系统实时更新显示位置。

二、代码

package ibeaconlocate;

import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.anthonycr.grant.PermissionsManager;
import com.anthonycr.grant.PermissionsResultAction;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

import CommonUtils.DeviceIDUitl;
import CommonUtils.TimeUtils;
import DbLibrary.DbManager;
import HttpUtils.ReqCallBack;
import HttpUtils.RequestManager;
import XyItemsRecycleradatper;
import IbeaconLibrary.BeaconType;
import IbeaconLibrary.BeaconUtils;
import IbeaconLibrary.BluetoothLeDevice;
import IbeaconLibrary.BluetoothLeDeviceStore;
import IbeaconLibrary.BluetoothLeScanner;
import IbeaconLibrary.BluetoothUtils;
import IbeaconLibrary.IbeaconLocateUtil;
import IbeaconLibrary.Point;


public class MainActivity extends AppCompatActivity{
    private BluetoothUtils mBluetoothUtils;
    private BluetoothLeScanner mScanner;
    private BluetoothLeDeviceStore mDeviceStore;

    private TextView txtViewX;
    private TextView txtViewY;

    private List<Point> mDatas;//扫描到的记录
    private XyItemsRecycleradatper recycleAdapter;//列表数据适配器

    private AndriodDevice mAndriodDevice;//巡检设备

    private RequestManager requestManager;


    //主入口点,初始化
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        txtViewX =(TextView)findViewById(R.id.textViewX);
        txtViewY=(TextView)findViewById(R.id.textViewY);
        mDeviceStore = new BluetoothLeDeviceStore();
        mBluetoothUtils = new BluetoothUtils(this);
        mScanner = new BluetoothLeScanner(mLeScanCallback, mBluetoothUtils);
        startScanPrepare();
    }

    /*
    菜单项初始化
     */
    @Override
    public boolean onCreateOptionsMenu(final Menu menu) {
        getMenuInflater().inflate(R.menu.ypontmain, menu);
        if (!mScanner.isScanning()) {
            menu.findItem(R.id.menu_stop).setVisible(false);
            menu.findItem(R.id.menu_scan).setVisible(true);

        } else {
            menu.findItem(R.id.menu_stop).setVisible(true);
            menu.findItem(R.id.menu_scan).setVisible(false);
        }
        if (mScanner.isCheck())
        {
            menu.findItem(R.id.menu_check).setVisible(false);
            menu.findItem(R.id.menu_noCheck).setVisible(true);
        }
        else
        {
            menu.findItem(R.id.menu_check).setVisible(true);
            menu.findItem(R.id.menu_noCheck).setVisible(false);
        }
        if (mScanner.isUpLocateData())
        {
            menu.findItem(R.id.menu_updata).setVisible(false);
            menu.findItem(R.id.menu_noupdata).setVisible(true);
        }
        else
        {
            menu.findItem(R.id.menu_updata).setVisible(true);
            menu.findItem(R.id.menu_noupdata).setVisible(false);
        }
        return true;
    }

    /*
    选择菜单项
     */
    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_scan:
                startScanPrepare();
                break;
            case R.id.menu_stop:
                mScanner.scanLeDevice(-1, false);
                invalidateOptionsMenu();
                break;
            case R.id.menu_check:
                mScanner.setCheck(mScanner.isScanning()?true:false);
                invalidateOptionsMenu();
                break;
            case R.id.menu_noCheck:
                mScanner.setCheck(false);
                invalidateOptionsMenu();
                break;
            case R.id.menu_clear:
                mDatas.clear();
                recycleAdapter.notifyDataSetChanged();
                break;
            case R.id.menu_updata:
                mScanner.setIsUpLocateData(true);
                invalidateOptionsMenu();
                break;
            case R.id.menu_noupdata:
                mScanner.setIsUpLocateData(false);
                invalidateOptionsMenu();
                break;
        }
        return true;
    }

    /*
    尝试开启蓝牙扫描
     */
    private void startScanPrepare() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(this,
                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, new PermissionsResultAction() {

                        @Override
                        public void onGranted() {
                            startScan();
                        }

                        @Override
                        public void onDenied(String permission) {
                            Toast.makeText(MainActivity.this,
                                    "访问蓝牙扫描结果需要访问权限!",
                                    Toast.LENGTH_SHORT)
                                    .show();
                        }
                    });
        } else {
            startScan();
        }
    }

    /*
    开始蓝牙扫描
     */
    private void startScan() {
        final boolean isBluetoothOn = mBluetoothUtils.isBluetoothOn();
        final boolean isBluetoothLePresent = mBluetoothUtils.isBluetoothLeSupported();
        mDeviceStore.clear();
        mBluetoothUtils.askUserToEnableBluetoothIfNeeded();
        InitRecyclerView();
        if (isBluetoothOn && isBluetoothLePresent) {
            mScanner.scanLeDevice(-1, true);
            invalidateOptionsMenu();
            mAndriodDevice =new AndriodDevice();
            requestManager=RequestManager.getInstance(MainActivity.this);
        }
    }

    /*
    初始化列表控件
     */
    private  void  InitRecyclerView()
    {
        mDatas = new ArrayList<Point>();
        recycleAdapter=new XyItemsRecycleradatper(this,mDatas);//条目适配器
        RecyclerView recyclerView=(RecyclerView) findViewById(R.id.recy_list);//列表控件
        LinearLayoutManager layoutManager = new LinearLayoutManager(this );
        recyclerView.setLayoutManager(layoutManager);

        recyclerView.setHasFixedSize(true);
        //创建并设置Adapter
        recyclerView.setAdapter(recycleAdapter);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
    }

    //蓝牙扫描回调函数
    private final BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {

            final BluetoothLeDevice deviceLe = new BluetoothLeDevice(device, rssi, scanRecord, System.currentTimeMillis());
            if (BeaconUtils.getBeaconType(deviceLe) == BeaconType.IBEACON)
            {
                if (deviceLe.getName()!=null) {
                    deviceLe.IbeaconLocateData= DbManager.onResume(MainActivity.this,deviceLe.getName());
                    if (deviceLe.IbeaconLocateData!= null)
                    {
                        mDeviceStore.addDevice(deviceLe);
                    }
                }
            }
            else
            {
                return;
            }
            List<BluetoothLeDevice> sortedDevices = IbeaconLocateUtil.GetSortedDevices(mDeviceStore);
            Point curLocatePoint=IbeaconLocateUtil.getLocateXY2(sortedDevices);
            if (IbeaconLocateUtil.isSameLocationValue(curLocatePoint))
            {
                return;
            }
            IbeaconLocateUtil.curLocatePoint=curLocatePoint;
            if (sortedDevices!=null&&!sortedDevices.isEmpty()&&mScanner.isCheck())
            {
                if (mScanner.isUpLocateData())
                {
                    reportLocateData(new Point(sortedDevices.get(0).IbeaconLocateData.getX(), sortedDevices.get(0).IbeaconLocateData.getY()));
                }
                double xCheck=sortedDevices.get(0).IbeaconLocateData.getX();
                double yCheck=sortedDevices.get(0).IbeaconLocateData.getY();
                if (mDatas.size()>50)
                {
                    mDatas.remove(mDatas.size()-1);
                }
                mDatas.add(0,new Point(xCheck,yCheck));
                recycleAdapter.notifyDataSetChanged();
            }
            else {
                if (curLocatePoint != null) {
                    if (mScanner.isUpLocateData())
                    {
                        reportLocateData(curLocatePoint);//提交定位数据到服务器
                    }
                    txtViewX.setText(String.valueOf(curLocatePoint.X));
                    txtViewY.setText(String.valueOf(curLocatePoint.Y));
                    if (mDatas.size() > 50) {
                        mDatas.remove(mDatas.size() - 1);
                    }
                    mDatas.add(0, new Point(curLocatePoint.X, curLocatePoint.Y));
                    recycleAdapter.notifyDataSetChanged();
                }
            }
        }
    };

    /*
    提交定位数据到服务器
     */
    private  void  reportLocateData(Point curLocatePoint)
    {
        mAndriodDevice.DeviceID= DeviceIDUitl.getDeviceId(MainActivity.this);
        mAndriodDevice.Devicename= DeviceIDUitl.getDeviceId(MainActivity.this);
        mAndriodDevice.DateTimeNow= TimeUtils.getNowDateTime("yyyy-MM-dd HH:mm:ss");
        mAndriodDevice.X=curLocatePoint.X;
        mAndriodDevice.Y=curLocatePoint.Y;
        mAndriodDevice.Xsbh="xs"+TimeUtils.getNowDateTime("yyyyMMddHHmmssSSS")+mAndriodDevice.DeviceID;
        LinkedHashMap<String,String> map=new LinkedHashMap<>();
        map.put("deviceid".toLowerCase(),mAndriodDevice.DeviceID);
        map.put("devicename".toLowerCase(),mAndriodDevice.Devicename);
        map.put("time".toLowerCase(),mAndriodDevice.DateTimeNow);
        map.put("x",String.valueOf(curLocatePoint.X));
        map.put("y",String.valueOf(curLocatePoint.Y));
        map.put("time".toLowerCase(),mAndriodDevice.DateTimeNow);
        map.put("xsbh",mAndriodDevice.Xsbh);
        requestManager.requestAsyn(RequestManager.BASE_URL, 0, map, new ReqCallBack<Object>() {
            @Override
            public  void  onReqSuccess(Object result)
            {
                //String resultMsg=String.valueOf(result);
            }
            @Override
            public  void  onReqFailed(String failMsg)
            {
                //String resultMsg=String.valueOf(failMsg);
            }

        });
    }
}
package IbeaconLibrary;

import java.util.ArrayList;
import java.util.List;


public class IbeaconLocateUtil {

    public  static Point curLocatePoint;

    public static boolean isSameLocationValue(Point p)
    {
        if (p==null)
        {
            return  false;
        }
        if (curLocatePoint==null)
        {
            return  false;
        }
        if (p.X==curLocatePoint.X&&p.Y==curLocatePoint.Y)
        {
            return  true;
        }
        else
        {
            return  false;
        }
    }

    public static Point getLocateXY(List<BluetoothLeDevice> curScanedDevices)
    {
        if (curScanedDevices==null||curScanedDevices.size()==0)
        {
            return  null;
        }
        else if (curScanedDevices.size()<=2)
        {
            int rssi=curScanedDevices.get(0).getRssi();
            return new Point(curScanedDevices.get(0).IbeaconLocateData.getX(),curScanedDevices.get(0).IbeaconLocateData.getY());
        }
        else
        {
            int rssi1=curScanedDevices.get(0).getRssi();
            double distance1= RSSIDistanceUitl.calculateAccuracy2(rssi1);
            int rssi2=curScanedDevices.get(1).getRssi();
            double distance2= RSSIDistanceUitl.calculateAccuracy2(rssi2);
            int rssi3=curScanedDevices.get(2).getRssi();
            double distance3= RSSIDistanceUitl.calculateAccuracy2(rssi3);
            Circle c1=new Circle(curScanedDevices.get(0).IbeaconLocateData.getX(),curScanedDevices.get(0).IbeaconLocateData.getY(), distance1);
            Circle c2=new Circle(curScanedDevices.get(1).IbeaconLocateData.getX(),curScanedDevices.get(1).IbeaconLocateData.getY(), distance2);
            Circle c3=new Circle(curScanedDevices.get(2).IbeaconLocateData.getX(),curScanedDevices.get(2).IbeaconLocateData.getY(), distance3);
            ThreeCircleIntersect threeCircleIntersect = new ThreeCircleIntersect(c1, c2, c3);
            Point point=threeCircleIntersect.GetThreeCircleIntersectPoint2(threeCircleIntersect.threeCirclePoints());
            return  point;
        }
    }

    //获取定位坐标
    public static Point getLocateXY2(List<BluetoothLeDevice> curScanedDevices)
    {
        List<Circle> lstCircles=getLocateCircles(curScanedDevices);//获取用于定位的信标节点
        Point resultLocatePoint=getLocateXY1(lstCircles,curScanedDevices);//定位坐标
        if (resultLocatePoint==null&&lstCircles!=null&&lstCircles.size()>=3)
        {
            resultLocatePoint=getLocateXY1(lstCircles.subList(0,2),curScanedDevices.subList(0,2));//定位坐标
        }
        if (lstCircles!=null&&lstCircles.size()>=3&&resultLocatePoint!=null)//修正坐标
        {
            Triangle triangle = new Triangle(new Point(lstCircles.get(0).getX(),lstCircles.get(0).getY()) ,new Point
                    (lstCircles.get(1).getX(),lstCircles.get(1).getY()),new Point(lstCircles.get(2).getX(),lstCircles.get(2).getY()));
            boolean isInOuterCircle=triangle.isPointInOuterCircle(resultLocatePoint);//定位坐标是否在信标节点的外接圆内
            if (!isInOuterCircle)
            {
                Point near2SidePoint=getNearst2Side2IbeaconsMiddlePoint(curScanedDevices);
                if (near2SidePoint!=null)
                {
                    return new Point(near2SidePoint.X,near2SidePoint.Y);
                }
                int rssi=curScanedDevices.get(0).getRssi();
                double distance = RSSIDistanceUitl.calculateAccuracy2(rssi);
                Circle c1=new Circle(curScanedDevices.get(0).IbeaconLocateData.getX(),curScanedDevices.get(0).IbeaconLocateData.getY(), distance);
                return new Point(c1.getX(),c1.getY());
            }
        }
        return  resultLocatePoint;
    }

    private static Point getNearst2Side2IbeaconsMiddlePoint(List<BluetoothLeDevice> curScanedDevices)
    {
        if (curScanedDevices==null||curScanedDevices.isEmpty()||curScanedDevices.size()<2)
        {
            return null;
        }
        List<BluetoothLeDevice> aSideDevices=new ArrayList<>();
        List<BluetoothLeDevice> bSideDevices=new ArrayList<>();
        for (BluetoothLeDevice leDevice:curScanedDevices)
        {
            if (leDevice.IbeaconLocateData!=null)
            {
                if (leDevice.IbeaconLocateData.getR()==0)
                {
                    aSideDevices.add(leDevice);
                }
                else if (leDevice.IbeaconLocateData.getR()==1)
                {
                    bSideDevices.add(leDevice);
                }
            }
        }
        if (aSideDevices.isEmpty()||bSideDevices.isEmpty())
        {
            return null;
        }
        else
        {
            class  Brother2SideIbeacons
            {
                public BluetoothLeDevice aSideIbeacon;
                public BluetoothLeDevice bSideIbeacon;
                public double distancePower;
                public Brother2SideIbeacons(BluetoothLeDevice l,BluetoothLeDevice ll,double disPower)
                {
                    this.aSideIbeacon=l;
                    this.bSideIbeacon=ll;
                    this.distancePower=disPower;
                }
            }
            List<Brother2SideIbeacons> brother2SideIbeacons=new ArrayList<>();
            for (BluetoothLeDevice l:aSideDevices)
            {
                for (BluetoothLeDevice ll:bSideDevices)
                {
                    double disPower=(l.IbeaconLocateData.getX()-ll.IbeaconLocateData.getX())*(l.IbeaconLocateData.getX()-ll.IbeaconLocateData.getX())
                            +(l.IbeaconLocateData.getY()-ll.IbeaconLocateData.getY())*(l.IbeaconLocateData.getY()-ll.IbeaconLocateData.getY());
                    Brother2SideIbeacons brother2SideIbeacons1=new Brother2SideIbeacons(l,ll,disPower);
                    brother2SideIbeacons.add(brother2SideIbeacons1);
                }
            }
            if (!brother2SideIbeacons.isEmpty())
            {
                Brother2SideIbeacons nearst2SideIbeacon=brother2SideIbeacons.get(0);
                int rssi2sideadded=brother2SideIbeacons.get(0).aSideIbeacon.getRssi()+brother2SideIbeacons.get(0).bSideIbeacon.getRssi();
                for (Brother2SideIbeacons bro:brother2SideIbeacons
                        ) {
                    int rssi=bro.aSideIbeacon.getRssi()+bro.bSideIbeacon.getRssi();
                    if (rssi>rssi2sideadded)
                    {
                        nearst2SideIbeacon=bro;
                    }
                }
                if (nearst2SideIbeacon!=null)
                {
                    double middleX=(nearst2SideIbeacon.aSideIbeacon.IbeaconLocateData.getX()+nearst2SideIbeacon.bSideIbeacon.IbeaconLocateData.getX())/2;
                    double middleY=(nearst2SideIbeacon.aSideIbeacon.IbeaconLocateData.getY()+nearst2SideIbeacon.bSideIbeacon.IbeaconLocateData.getY())/2;
                    return  new Point(middleX,middleY);

                }
            }
        }
        return  null;
    }

    private static Point getLocateXY1(List<Circle> circles,List<BluetoothLeDevice> curScanedDevices)
    {
        if (circles==null||circles.size()==0)
        {
            return  null;
        }
        else if (circles.size()<=2||curScanedDevices.size()<=2)
        {
            if (circles.size()==2||curScanedDevices.size()==2)
            {
                Point near2SidePoint=getNearst2Side2IbeaconsMiddlePoint(curScanedDevices);
                if (near2SidePoint!=null)
                {
                    return new Point(near2SidePoint.X,near2SidePoint.Y);
                }
            }
            return  new Point(circles.get(0).getX(),circles.get(0).getY());
        }
        else
        {
            ThreeCircleIntersect threeCircleIntersect = new ThreeCircleIntersect(circles.get(0), circles.get(1), circles.get(2));
            Circle bothIntersectC = CirIntersect.getBothIntersectCircles(circles.get(0),circles.get(1),circles.get(2));

            if (bothIntersectC!=null&&!CirIntersect.siAllCirclesIntersect(circles.get(0),circles.get(1),circles.get(2)))
            {
                Point point = threeCircleIntersect.GetThreeCircleIntersectPoint2(threeCircleIntersect.oneCircleIntersecttwoCircles());

                return  point;
            }
            if (CirIntersect.siAllCirclesIntersect(circles.get(0),circles.get(1),circles.get(2)))
            {
                Point point = threeCircleIntersect.GetThreeCircleIntersectPoint2(threeCircleIntersect.threeCirclePoints());
                return  point;
            }
            return  null;
        }
    }

    private static List<Circle> getLocateCircles(List<BluetoothLeDevice> curScanedDevices)
    {
        List<Circle> resultC=new ArrayList<>();
        if (curScanedDevices==null||curScanedDevices.size()==0)
        {
            return  null;
        }
        else if (curScanedDevices.size()==1)
        {
            int rssi=curScanedDevices.get(0).getRssi();
            double distance = RSSIDistanceUitl.calculateAccuracy2(rssi);
            Circle c1=new Circle(curScanedDevices.get(0).IbeaconLocateData.getX(),curScanedDevices.get(0).IbeaconLocateData.getY(), distance);
            resultC.add(c1);
            return  resultC;
        }
        else
        {
            for (BluetoothLeDevice l : curScanedDevices)
            {
                int rssi=l.getRssi();
                double distance = RSSIDistanceUitl.calculateAccuracy2(rssi);
                Circle c1=new Circle(l.IbeaconLocateData.getX(),l.IbeaconLocateData.getY(), distance);
                resultC.add(c1);
            }
            return  CirIntersect.getLocateCircles(resultC);
        }
    }

    public static List<BluetoothLeDevice> GetSortedDevices(BluetoothLeDeviceStore leDeviceStore)
    {
        List<BluetoothLeDevice> bluetoothLeDevices=new ArrayList<>();

        List<BluetoothLeDevice> beforeSortDevices = leDeviceStore.getDeviceList();
        BluetoothLeDevice tempSortDevice;
        if (beforeSortDevices.size()>1)
        {
            for (int i = 0; i < beforeSortDevices.size() - 1; i++)
            {
                for (int j = i+1; j < beforeSortDevices.size(); j++)
                {
                    if (beforeSortDevices.get(i).getRssi()<beforeSortDevices.get(j).getRssi())
                    {
                        tempSortDevice=beforeSortDevices.get(i);
                        beforeSortDevices.set(i,beforeSortDevices.get(j));
                        beforeSortDevices.set(j,tempSortDevice);
                    }
                }
            }
        }
        for (int i=0;i<beforeSortDevices.size();i++)
        {
            bluetoothLeDevices.add(beforeSortDevices.get(i));
        }
        return bluetoothLeDevices;
    }





}

 

posted on 2021-01-27 14:32  苹果园dog  阅读(1158)  评论(0编辑  收藏  举报

导航