发布时间:2025-12-09 18:01:17 浏览次数:6
一、简介
室内部署蓝牙信标,移动端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;//主入口点,初始化@Overrideprotected 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();}/*菜单项初始化*/@Overridepublic 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;}/*选择菜单项*/@Overridepublic 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() {@Overridepublic void onGranted() {startScan();}@Overridepublic 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);//创建并设置AdapterrecyclerView.setAdapter(recycleAdapter);recyclerView.setItemAnimator(new DefaultItemAnimator());}//蓝牙扫描回调函数private final BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {@Overridepublic 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>() {@Overridepublic void onReqSuccess(Object result){//String resultMsg=String.valueOf(result);}@Overridepublic 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;}