Commit 3387f2d5 authored by y0no's avatar y0no
Browse files

First commit

parents
# Built application files
*.apk
*.ap_
# Files for the ART/Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
# Intellij
*.iml
.idea/workspace.xml
.idea/libraries
# Keystore files
*.jks
NewBtLE
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
<entry name="!?*.aj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>
\ No newline at end of file
<component name="CopyrightManager">
<settings default="" />
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="myModules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/NewBtLE.iml" filepath="$PROJECT_DIR$/NewBtLE.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>
\ No newline at end of file
# Introduction
This android app is a fork from app used in Probezero project to scan all BLE devices with an android smartphone. If you don't know what is Probezero, go see it
right now: https://github.com/virtualabs/probeZero/
This app is aimed to be more battery efficient than the original one and to be compatible with Android marshmallow
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "24.0.0"
defaultConfig {
applicationId "fr.y0no.newbtle"
minSdkVersion 21
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.0.0'
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/y0no/Android/Sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
package fr.y0no.newbtle;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="fr.y0no.newbtle">
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".NewBtLE" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
\ No newline at end of file
package fr.y0no.newbtle;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.util.Log;
import android.widget.ListView;
import android.widget.TextView;
import java.util.HashMap;
import java.util.List;
/**
* Created by y0no on 07/07/16.
*/
public class BtScanner {
private final static String TAG = "NewBTLE/Scanner";
private BluetoothAdapter m_oAdapter;
private BluetoothLeScanner m_oScanner;
private DeviceAdapter m_oUiAdapter;
private TextView m_oStatus;
private ListView m_oList;
private Context m_oContext;
private List<ScanFilter> m_lFilter;
private ScanSettings m_oSettings;
private HashMap<String, DeviceInfo> m_oDetectedDevices;
public BtScanner(Context context, TextView status, ListView list) {
m_oContext = context;
m_oStatus = status;
m_oList = list;
m_oUiAdapter = (DeviceAdapter)m_oList.getAdapter();
m_oAdapter = BluetoothAdapter.getDefaultAdapter();
if (m_oAdapter == null) {
m_oStatus.setText("No adapter found");
Log.d(TAG, "No adapter found");
} else {
Log.d(TAG, m_oAdapter.getName());
}
m_oScanner = m_oAdapter.getBluetoothLeScanner();
if (m_oScanner == null) {
m_oStatus.setText("Unable to get LE Scanner");
}
m_oDetectedDevices = new HashMap<String, DeviceInfo>();
}
public boolean enableAdapter() {
if (!m_oAdapter.isEnabled()) {
return m_oAdapter.enable();
}
return true;
}
public void startScan() {
if (!enableAdapter())
return;
m_oStatus.setText("Scanning...");
m_oScanner.startScan(mLeScanCallback);
}
private ScanCallback mLeScanCallback =
new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice oBtDevice = result.getDevice();
addOrUpdateDevice(
oBtDevice,
result.getScanRecord().getBytes(),
result.getTimestampNanos(),
result.getRssi()
);
}
};
private void addOrUpdateDevice(BluetoothDevice device, byte[] scanRecord,
long timestamp, int rssi){
if(!m_oDetectedDevices.containsKey(device.getAddress())){
Log.d(TAG, "Add new device to list : " + device.getName());
DeviceInfo deviceInfo = new DeviceInfo(
device, scanRecord, timestamp, rssi
);
m_oUiAdapter.add(deviceInfo);
m_oDetectedDevices.put(device.getAddress(), deviceInfo);
} else {
Log.d(TAG, "Updating : " + device.getName() + " (" + device.getAddress() + ")");
DeviceInfo deviceInfo = m_oDetectedDevices.get(device.getAddress());
deviceInfo.setM_lLastSeen(timestamp);
deviceInfo.setM_iRssi(rssi);
}
m_oList.setAdapter(m_oUiAdapter);
}
}
package fr.y0no.newbtle;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
/**
* Created by y0no on 08/07/16.
*/
public class DeviceAdapter extends ArrayAdapter<DeviceInfo> {
public class Holder
{
TextView address;
TextView name;
TextView rssi;
}
public DeviceAdapter(Context context, int textViewResourceId, List<DeviceInfo> collection) {
super(context, textViewResourceId, collection);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder h;
DeviceInfo p = getItem(position);
if (p != null) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.device_item, null);
h = new Holder();
h.name = (TextView) convertView.findViewById(R.id.tDeviceName);
h.address = (TextView) convertView.findViewById(R.id.tDeviceMac);
h.rssi = (TextView) convertView.findViewById(R.id.tRssi);
convertView.setTag(h);
} else {
h = (Holder)convertView.getTag();
}
h.name.setText(p.getDeviceName());
h.address.setText(p.getMacAddress());
h.rssi.setText("RSSI: " + String.valueOf(p.getM_iRssi()));
} else {
Log.e("DeviceAdapter", "item is null");
}
return convertView;
}
}
package fr.y0no.newbtle;
import android.bluetooth.BluetoothDevice;
import fr.y0no.newbtle.utils.ADParser;
/**
* Created by y0no on 07/07/16.
*/
public class DeviceInfo {
private BluetoothDevice m_oDevice;
private byte[] m_bData;
private long m_lFirstSeen;
private long m_lLastSeen;
private int m_iRssi;
private FingerprintMgr.DeviceSignature m_oSignature;
public DeviceInfo(BluetoothDevice device, byte[] data, long firstSeen, int Rssi) {
m_oDevice = device;
m_bData = data;
m_lFirstSeen = m_lLastSeen = firstSeen;
m_iRssi = Rssi;
ADParser.parse(m_bData);
}
public String getDeviceName() {
return m_oDevice.getName();
}
public String getMacAddress() {
return m_oDevice.getAddress();
}
public int getM_iRssi() {
return m_iRssi;
}
public void setM_iRssi(int m_iRssi) {
this.m_iRssi = m_iRssi;
}
public long getM_lLastSeen() {
return m_lLastSeen;
}
public void setM_lLastSeen(long m_lLastSeen) {
this.m_lLastSeen = m_lLastSeen;
}
public byte[] getM_bData() {
return m_bData;
}
public void setM_bData(byte[] m_bData) {
this.m_bData = m_bData;
}
}
package fr.y0no.newbtle;
import android.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import fr.y0no.newbtle.utils.ADParser;
/**
* Created by y0no on 08/07/16.
*/
public class FingerprintMgr {
public enum DEVICE_TYPE {
UNKNOWN,
PHONE,
APPLE,
FITBIT,
SMARTLOCK,
KEYFOB,
WRISTBAND,
HEARTBEAT,
SMARTWATCH,
SOUND
};
public class DeviceSignature {
private DEVICE_TYPE mType;
private String mName;
DeviceSignature(DEVICE_TYPE type, String name) {
mType = type;
mName = name;
}
public String getName() { return mName; }
public DEVICE_TYPE getType() { return mType; }
}
private static HashMap<String, DeviceSignature> m_oSignatures = new HashMap<>();
public static boolean isKnown(String address) {
for (Map.Entry<String, DeviceSignature> entry: m_oSignatures.entrySet()) {
if (entry.getValue().mName == address)
return true;
}
return false;
}
public static void addSignature(String name, DeviceSignature signature) {
m_oSignatures.put(name, signature);
}
public static DeviceSignature getSignature(DeviceInfo device) {
return m_oSignatures.get(device.getDeviceName());
}
private byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len/2];
for(int i = 0; i < len; i+=2){
data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16));
}
return data;
}
private String convertStringToHex(byte[] buf)
{
final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
char[] chars = new char[2 * buf.length];
for (int i = 0; i < buf.length; ++i)
{
chars[2 * i] = HEX_CHARS[(buf[i] & 0xF0) >>> 4];
chars[2 * i + 1] = HEX_CHARS[buf[i] & 0x0F];
}
return new String(chars);
}
private boolean compareSignature(ArrayList<ADParser.Record> records, String signature) {
return false;
}
}
package fr.y0no.newbtle;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ListView;
import android.widget.TextView;