diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39fb081 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..7ac24c7 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..ee7a204 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..1701897 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..b97788b --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,39 @@ +apply plugin: 'com.android.application' + +apply plugin: 'kotlin-android' + +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 26 + defaultConfig { + applicationId "suer_fi.developmentkitapp" + minSdkVersion 21 + targetSdkVersion 26 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" + implementation 'com.android.support:appcompat-v7:26.1.0' + implementation 'com.android.support.constraint:constraint-layout:1.0.2' + implementation 'com.android.support:design:26.1.0' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.1' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' + compile "org.jetbrains.anko:anko:$anko_version" + compile "org.jetbrains.anko:anko-commons:$anko_version" + compile "org.jetbrains.anko:anko-design:$anko_version" // For SnackBars + compile "com.android.support:recyclerview-v7:26.1.0" + +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# 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 *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/src/androidTest/java/suer_fi/developmentkitapp/ExampleInstrumentedTest.kt b/app/src/androidTest/java/suer_fi/developmentkitapp/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..a3186c0 --- /dev/null +++ b/app/src/androidTest/java/suer_fi/developmentkitapp/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package suer_fi.developmentkitapp + +import android.support.test.InstrumentationRegistry +import android.support.test.runner.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getTargetContext() + assertEquals("suer_fi.developmentkitapp", appContext.packageName) + } +} diff --git a/app/src/drawable-hdpi/bluetooth.png b/app/src/drawable-hdpi/bluetooth.png new file mode 100755 index 0000000..51bb2c7 Binary files /dev/null and b/app/src/drawable-hdpi/bluetooth.png differ diff --git a/app/src/drawable-ldpi/bluetooth.png b/app/src/drawable-ldpi/bluetooth.png new file mode 100755 index 0000000..3158f06 Binary files /dev/null and b/app/src/drawable-ldpi/bluetooth.png differ diff --git a/app/src/drawable-mdpi/bluetooth.png b/app/src/drawable-mdpi/bluetooth.png new file mode 100755 index 0000000..dc96ead Binary files /dev/null and b/app/src/drawable-mdpi/bluetooth.png differ diff --git a/app/src/drawable-xhdpi/bluetooth.png b/app/src/drawable-xhdpi/bluetooth.png new file mode 100755 index 0000000..da0d875 Binary files /dev/null and b/app/src/drawable-xhdpi/bluetooth.png differ diff --git a/app/src/drawable-xxhdpi/bluetooth.png b/app/src/drawable-xxhdpi/bluetooth.png new file mode 100755 index 0000000..a42e909 Binary files /dev/null and b/app/src/drawable-xxhdpi/bluetooth.png differ diff --git a/app/src/drawable-xxxhdpi/bluetooth.png b/app/src/drawable-xxxhdpi/bluetooth.png new file mode 100755 index 0000000..1d2d801 Binary files /dev/null and b/app/src/drawable-xxxhdpi/bluetooth.png differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..e83a7c2 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/suer_fi/developmentkitapp/BluetoothPeripheral.kt b/app/src/main/java/suer_fi/developmentkitapp/BluetoothPeripheral.kt new file mode 100644 index 0000000..2b15707 --- /dev/null +++ b/app/src/main/java/suer_fi/developmentkitapp/BluetoothPeripheral.kt @@ -0,0 +1,71 @@ +package suer_fi.developmentkitapp + +import android.bluetooth.BluetoothDevice +import android.os.Parcel +import android.os.Parcelable + +/** + * Created by sure-fi on 1/23/18. + */ + + + + +open class BluetoothPeripheral( + val address: String, + val name: String, + val device_id: String, + val hardware_type: String, + val device_status: String, + val firmware_version: String? = null, + val paired_id: String? = null, + val security_string : String? = null, + val manufacturer_data : String? = null, + var bluetooth_device : BluetoothDevice? = null + +): Parcelable { + + constructor(parcel: Parcel) : this( + parcel.readString(), + parcel.readString(), + parcel.readString(), + parcel.readString(), + parcel.readString(), + parcel.readString(), + parcel.readString(), + parcel.readString(), + parcel.readString(), + parcel.readParcelable(BluetoothDevice::class.java.classLoader)) {} + + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(address) + parcel.writeString(name) + parcel.writeString(device_id) + parcel.writeString(hardware_type) + parcel.writeString(device_status) + parcel.writeString(firmware_version) + parcel.writeString(paired_id) + parcel.writeString(security_string) + parcel.writeString(manufacturer_data) + parcel.writeParcelable(bluetooth_device, flags) + } + + + private fun calculateSecurityString() : ByteArray { + + var peripheralRXUUID = this.device_id.toUpperCase().reversed() + var peripheralTXUUID = this.paired_id?.toUpperCase() + "x~sW5-C\"6fu>!!~X" + var final_string = peripheralRXUUID + peripheralTXUUID + + return final_string.md5().toByteArray() + } + + companion object { + @JvmField @Suppress("unused") + val CREATOR = createParcel{BluetoothPeripheral(it)} + } + + override fun describeContents() = 0 +} + diff --git a/app/src/main/java/suer_fi/developmentkitapp/Constants.kt b/app/src/main/java/suer_fi/developmentkitapp/Constants.kt new file mode 100644 index 0000000..b311089 --- /dev/null +++ b/app/src/main/java/suer_fi/developmentkitapp/Constants.kt @@ -0,0 +1,16 @@ +package suer_fi.developmentkitapp + +/** + * Created by sure-fi on 1/25/18. + */ +class Constants { + companion object { + val MODULE_TYPE = "00" + val WIEGAND_TYPE = "01" + val REMOTE_TYPE = "02" + val HVAC_THERMOSTAT_TYPE = "03" + val HVAC_EQUIPMENT_TYPE = "04" + val SERIAL_DATA__CENTRAL_TYPE = "05" + val SERIAL_DATA_REMOTE_TYPE = "06" + } +} \ No newline at end of file diff --git a/app/src/main/java/suer_fi/developmentkitapp/Devices.kt b/app/src/main/java/suer_fi/developmentkitapp/Devices.kt new file mode 100644 index 0000000..ed8ee71 --- /dev/null +++ b/app/src/main/java/suer_fi/developmentkitapp/Devices.kt @@ -0,0 +1,340 @@ +package suer_fi.developmentkitapp + +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothManager +import android.bluetooth.le.BluetoothLeScanner +import android.bluetooth.le.ScanCallback +import android.bluetooth.le.ScanResult +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.support.v7.app.AppCompatActivity +import android.util.Log +import android.support.v4.app.ActivityCompat +import android.content.pm.PackageManager +import android.Manifest.permission.ACCESS_FINE_LOCATION +import android.annotation.SuppressLint +import android.app.Activity +import android.os.Parcel +import android.os.Parcelable +import android.support.v4.content.ContextCompat +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.LinearLayout +import kotlinx.android.synthetic.main.main_device_activity.* +import org.jetbrains.anko.alert +import org.jetbrains.anko.okButton +import org.jetbrains.anko.toast +import java.util.* +import kotlin.concurrent.schedule + +class Devices : AppCompatActivity(), ActivityCompat.OnRequestPermissionsResultCallback{ + + private var devices: ArrayList = ArrayList() + private var mRecyclerView : RecyclerView? = null + private var mAdapter : DevicesAdapter? = null + private var mLayoutManager: RecyclerView.LayoutManager? = null + private var bluetoothManager: BluetoothManager? = null + private var bluetoothAdapter: BluetoothAdapter? = null + private var bluetoothScanner: BluetoothLeScanner? = null + private var menu: Menu? = null + private var scanButton : MenuItem? = null + private var stopScanButton : MenuItem? = null + private var scanCallback : ScanCallback? = null + + companion object { + val REQUEST_PERMISSION = 1 + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.main_device_activity) + checkPermissionsStatus() + } + + private fun initRecyclerViewList(){ + mRecyclerView = my_recycler_view + mLayoutManager = LinearLayoutManager(this) + + if(bluetoothScanner == null){ + initBluetooth() + } + + mAdapter = DevicesAdapter(devices,this) + mRecyclerView?.layoutManager = mLayoutManager + mRecyclerView?.adapter = mAdapter + } + + private fun initBluetoothManager(){ + if(bluetoothManager == null){ + bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager? + } + } + + private fun initBluetoothAdapter(){ + if(bluetoothManager != null){ + bluetoothAdapter = bluetoothManager?.adapter + } + } + + private fun initBluetoothScanner(){ + if(bluetoothAdapter != null){ + bluetoothScanner = bluetoothAdapter?.bluetoothLeScanner + } + } + + private fun initBluetooth(){ + initBluetoothManager() + initBluetoothAdapter() + initBluetoothScanner() + } + + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + menuInflater.inflate(R.menu.menu_devices,menu); + this.menu = menu + this.scanButton = menu?.findItem(R.id.scan) + this.stopScanButton = menu?.findItem(R.id.stop_scan) + return true + } + + override fun onOptionsItemSelected(item: MenuItem?): Boolean { + var id = item?.itemId + + if(id == R.id.scan){ + updateViewAfterStartScan() + this.scanForDevices() + } + + if(id == R.id.stop_scan){ + hideStopScanButton() + showScanButton() + this.stopScan() + } + + return super.onOptionsItemSelected(item) + } + + private fun checkPermissionsStatus(){ + Log.d("DEBUG","checkPermissionsStatus") + if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.ACCESS_FINE_LOCATION)) { + alert("In order to use the Bluetooth we will need activate the location services on the app.") { + title = "Location services required" + okButton { + requestLocationPermission() + } + }.show() + + } else { + requestLocationPermission() + } + }else{ + val mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter() + if (mBluetoothAdapter == null) { + alert { "The device does not support Bluetooth." }.show() + } else { + if (!mBluetoothAdapter.isEnabled) { + requestBluetooth() + }else{ + prepareForScan() + } + } + } + } + + private fun prepareForScan(){ + initBluetooth() + hideLocationServicesNeededScreen() + hideBluetoothServicesNeededScreen() + hideScanButton() + showStopScanButton() + showScanActivity() + scanForDevices() + initRecyclerViewList() // always should be called after initBluetooth + } + + fun activateLocationsBtnPressed(view: View){ + requestLocationPermission() + } + + fun activityBluetoothBtnPressed(view: View){ + requestBluetooth() + } + + fun requestLocationPermission(){ + Log.d("DEBUG","requestLocationPermission") + val permissionGranted = ActivityCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED + if(permissionGranted){ + hideLocationServicesNeededScreen() + requestBluetooth() + }else{ + ActivityCompat.requestPermissions(this, arrayOf(ACCESS_FINE_LOCATION), REQUEST_PERMISSION) + } + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + Log.d("DEBUG","onRequestPermissionsResult ${requestCode}") + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + if(grantResults[0] == 0){ + hideLocationServicesNeededScreen() + requestBluetooth() + }else{ + showLocationServicesNeededScreen() + } + } + + private fun showLocationServicesNeededScreen(){ + var layout = findViewById(R.id.activate_location_layout) + layout.visibility = View.VISIBLE + } + + private fun hideLocationServicesNeededScreen(){ + var layout = findViewById(R.id.activate_location_layout) + layout.visibility = View.GONE + } + + private fun showBluetoothServicesNeededScreen(){ + findViewById(R.id.activate_bluetooth_layout).visibility = View.VISIBLE + } + + private fun hideBluetoothServicesNeededScreen(){ + findViewById(R.id.activate_bluetooth_layout).visibility = View.GONE + } + + fun requestBluetooth(){ + Log.d("DEBUG","requestBluetooth") + val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) + val request_enabled_bt = 1 + startActivityForResult(enableBtIntent, request_enabled_bt) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + Log.d("DEBUG","onActivityResult ${requestCode} ${resultCode} ") + if(resultCode == Activity.RESULT_OK){ + prepareForScan() + }else{ + showBluetoothServicesNeededScreen() + } + } + + fun showScanActivity(){ + var layer = findViewById(R.id.scanning_div) + layer.visibility = View.VISIBLE + } + + fun hideScanActivity(){ + var layer = findViewById(R.id.scanning_div) + layer.visibility = View.GONE + } + + fun hideStopScanButton(){ + menu?.findItem(R.id.stop_scan)?.setVisible(false) + } + + fun showStopScanButton(){ + menu?.findItem(R.id.stop_scan)?.setVisible(true) + } + + fun showScanButton(){ + menu?.findItem(R.id.scan)?.setVisible(true); + } + + fun hideScanButton(){ + menu?.findItem(R.id.scan)?.setVisible(false); + } + + private fun updateViewAfterStopScan(){ + showScanButton() + hideStopScanButton() + hideScanActivity() + } + + private fun updateViewAfterStartScan(){ + hideScanButton() + showStopScanButton() + showScanActivity() + clearDevices() + } + + private fun clearDevices(){ + devices.clear() + } + + private fun scanForDevices(){ + Log.d("DEBUG","scanForDevices") + + scanCallback = object: ScanCallback(){ + override fun onScanResult(callbackType: Int, result: ScanResult) { + super.onScanResult(callbackType, result) + if(result.device.name != null){ + if(result.device.name.contains("Sure-Fi")){ + val bytes = result.scanRecord.manufacturerSpecificData + + var manufacturer_data = "" + + if (bytes.valueAt(0) != null) { + manufacturer_data= bytes.valueAt(0).toHex() + } + + val hardware_type = manufacturer_data.substring(IntRange(0,1)) + val device_status = manufacturer_data.substring(IntRange(6,7) ) + val device_id = manufacturer_data.substring(IntRange(7,13)) + val paired_id = manufacturer_data.substring(IntRange(13,19)) + var contains = false + + for (temp_device in devices){ + if(temp_device.device_id == device_id) + contains = true + } + + if(!contains){ + val device = BluetoothPeripheral( + address = result.device.address, + name = result.device.name, + hardware_type = hardware_type, + device_status = device_status, + device_id = device_id, + paired_id = paired_id, + manufacturer_data = manufacturer_data, + bluetooth_device = result.device + ) + + devices.add(device) + mAdapter?.notifyItemInserted(devices.size - 1) + //Log.d("ScanDeviceActivity","${device.hardware_type} ${device.device_status} ${device.device_id} ${device.paired_id}") + } + } + } + } + } + + bluetoothScanner?.startScan(scanCallback) + this.stopScanAfterSeconds() + } + + private fun stopScanAfterSeconds(time : Long = 20000){ + Log.d("DEBUG","stopScanAfterSeconds") + Timer().schedule(time){ + Log.d("DEBUG","111") + stopScan() + Log.d("DEBUG","111") + } + } + + fun stopScan(){ + Log.d("DEBUG","stopScan()") + if(bluetoothScanner != null){ + bluetoothScanner?.stopScan(scanCallback) + runOnUiThread { + updateViewAfterStopScan() + } + }else{ + toast("Error the scanner can't be stoped") + } + } + +} diff --git a/app/src/main/java/suer_fi/developmentkitapp/DevicesAdapter.kt b/app/src/main/java/suer_fi/developmentkitapp/DevicesAdapter.kt new file mode 100644 index 0000000..d18bb17 --- /dev/null +++ b/app/src/main/java/suer_fi/developmentkitapp/DevicesAdapter.kt @@ -0,0 +1,100 @@ +package suer_fi.developmentkitapp + +import android.bluetooth.le.BluetoothLeScanner +import android.content.Context +import android.content.Intent +import android.os.Parcelable +import android.support.v4.content.ContextCompat +import android.support.v7.widget.RecyclerView +import android.util.Log +import android.view.View +import android.view.ViewGroup +import kotlinx.android.synthetic.main.device_list_item.view.* + +/** + * Created by sure-fi on 1/24/18. + */ +class DevicesAdapter( + private val devices: ArrayList, + val context: Context) : RecyclerView.Adapter(){ + + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DeviceHolder { + val inflatedView = parent.inflate(R.layout.device_list_item, false) + return DeviceHolder(inflatedView,context) + } + + override fun onBindViewHolder(holder: DeviceHolder, position: Int) { + val itemDevice = devices[position] + holder.bindInfo(itemDevice) + holder.bindInfo(itemDevice) + } + + override fun getItemCount() = devices.size + + + class DeviceHolder(v: View,context:Context) : RecyclerView.ViewHolder(v), View.OnClickListener{ + private var view = v + private var device:BluetoothPeripheral? = null + private var context = context + + init { + v.setOnClickListener(this) + } + + override fun onClick(v: View?) { + + stopDevicesScan() + + var bluetoothPeripheral : BluetoothPeripheral = device as BluetoothPeripheral + var i = Intent(context,ModuleInterface::class.java) + + i.putExtra("device",bluetoothPeripheral) + context.startActivity(i) + } + + private fun stopDevicesScan(){ + Log.d("DEBUG",device?.name) + var devices = context as Devices + if(devices is Devices){ + devices.stopScan() + }else{ + Log.w("DEBUG","Error Callback to the scanner references loose.") + } + } + + + /* + * @return the return structure have the next form ["Name of the module", "Background color of the module","color text"] + * */ + private fun choseTypesAttributes(hardware_type:String) : Array{ + + when(hardware_type){ + "00" -> return arrayOf("Sure-Fi Module",R.drawable.sure_fi_module_rectangle,R.color.colorWhite) + "01" -> return arrayOf("Wiegand Central",R.drawable.wiegand_central_rectangle,R.color.colorWhite) + "02" -> return arrayOf("Wiegand Remote",R.drawable.wiegand_remote_rectangle,R.color.colorWiegandCentral) + "03" -> return arrayOf("HVAC Thermostat",R.drawable.hvac_thermostat_rectangle,R.color.colorWhite) + "04" -> return arrayOf("HVAC Equipment",R.drawable.hvac_equipment_rectangle,R.color.colorHVACThermostat) + "05" -> return arrayOf("Serial Data Central",R.drawable.serial_data_central_rectangle,R.color.colorWhite) + "06" -> return arrayOf("Serial Data Remote",R.drawable.serial_data_remote_rectangle,R.color.colorWhite) + else -> return arrayOf("No option found to ${hardware_type} type",R.color.colorUknownType,R.color.colorWhite) + } + } + + fun bindInfo(device: BluetoothPeripheral){ + val types = choseTypesAttributes(device.hardware_type) + this.device = device + view.name.text = device.name + view.device_id.text = device.device_id + view.manufacturer_data.text = device.manufacturer_data + view.hardware_type.text = types.get(0) as String + view.hardware_type.setBackgroundResource(types.get(1) as Int); + view.hardware_type.setTextColor(ContextCompat.getColor(context,types.get(2) as Int)) + } + + companion object { + //5 + private val DEVICE_KEY = "DEVICE" + } + } +} \ No newline at end of file diff --git a/app/src/main/java/suer_fi/developmentkitapp/DevicesLayoutManager.kt b/app/src/main/java/suer_fi/developmentkitapp/DevicesLayoutManager.kt new file mode 100644 index 0000000..a497261 --- /dev/null +++ b/app/src/main/java/suer_fi/developmentkitapp/DevicesLayoutManager.kt @@ -0,0 +1,9 @@ +package suer_fi.developmentkitapp + + +import android.support.v7.widget.RecyclerView.LayoutManager +/** + * Created by sure-fi on 1/24/18. + */ +class DevicesLayoutManager{ +} \ No newline at end of file diff --git a/app/src/main/java/suer_fi/developmentkitapp/Extensions.kt b/app/src/main/java/suer_fi/developmentkitapp/Extensions.kt new file mode 100644 index 0000000..20f6ee5 --- /dev/null +++ b/app/src/main/java/suer_fi/developmentkitapp/Extensions.kt @@ -0,0 +1,46 @@ +package suer_fi.developmentkitapp + +import android.os.Parcel +import android.os.Parcelable +import android.support.annotation.LayoutRes +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import java.security.MessageDigest + +fun ViewGroup.inflate(@LayoutRes layoutRes: Int, attachToRoot: Boolean = false): View { + return LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot) +} + +private val HEX_CHARS = "0123456789ABCDEF".toCharArray() + +fun ByteArray.toHex() : String{ + val result = StringBuffer() + + forEach { + val octet = it.toInt() + val firstIndex = (octet and 0xF0).ushr(4) + val secondIndex = octet and 0x0F + result.append(HEX_CHARS[firstIndex]) + result.append(HEX_CHARS[secondIndex]) + } + + return result.toString() +} + + + +fun String.md5(): String { + val md = MessageDigest.getInstance("MD5") + val digested = md.digest(toByteArray()) + return digested.joinToString("") { + String.format("%02x", it) + } +} + +inline fun createParcel( + crossinline createFromParcel: (Parcel) -> T?): Parcelable.Creator = + object : Parcelable.Creator { + override fun createFromParcel(source: Parcel): T? = createFromParcel(source) + override fun newArray(size: Int): Array = arrayOfNulls(size) + } \ No newline at end of file diff --git a/app/src/main/java/suer_fi/developmentkitapp/MainActivity.kt b/app/src/main/java/suer_fi/developmentkitapp/MainActivity.kt new file mode 100644 index 0000000..66dc8be --- /dev/null +++ b/app/src/main/java/suer_fi/developmentkitapp/MainActivity.kt @@ -0,0 +1,28 @@ +package suer_fi.developmentkitapp + +import android.content.Intent +import android.support.v7.app.AppCompatActivity +import android.os.Bundle +import android.util.Log +import android.view.View +import android.support.v7.widget.RecyclerView +import android.support.v7.widget.RecyclerView.Adapter + + +data class Item(val id: Long, val title: String, val url: String) + + +class MainActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + } + + /** Called when the user taps the Send button */ + fun goToDevices(view: View) { + val intent = Intent(this,Devices::class.java) + startActivity(intent) + } + +} diff --git a/app/src/main/java/suer_fi/developmentkitapp/MainTabFragment.kt b/app/src/main/java/suer_fi/developmentkitapp/MainTabFragment.kt new file mode 100644 index 0000000..2f3e0ed --- /dev/null +++ b/app/src/main/java/suer_fi/developmentkitapp/MainTabFragment.kt @@ -0,0 +1,41 @@ +package suer_fi.developmentkitapp + +import android.bluetooth.BluetoothGatt +import android.bluetooth.BluetoothGattCallback +import android.os.Bundle +import android.support.v4.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import kotlinx.android.synthetic.main.fragment_page.* + +/** + * Created by sure-fi on 1/31/18. + */ +class MainTabFragment : Fragment() { + + private var device: BluetoothPeripheral? = null + private var bluetoothGattCallback : BluetoothGattCallback? = null + private var bluetoothGatt : BluetoothGatt? = null + + + companion object { + val PAGE_NUM = "PAGE_NUM" + + fun newInstance(): MainTabFragment { + + /*val fragment = MainTabFragment() + val args = Bundle() + args.putInt(PAGE_NUM, page) + fragment.setArguments(args)*/ + return MainTabFragment() + } + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val view = inflater.inflate(R.layout.main_tab_fragment, container, false) + val page = getArguments().getInt(PAGE_NUM) + return view + } +} \ No newline at end of file diff --git a/app/src/main/java/suer_fi/developmentkitapp/ManufacturerData.kt b/app/src/main/java/suer_fi/developmentkitapp/ManufacturerData.kt new file mode 100644 index 0000000..0d26621 --- /dev/null +++ b/app/src/main/java/suer_fi/developmentkitapp/ManufacturerData.kt @@ -0,0 +1,14 @@ +package suer_fi.developmentkitapp + +/** + * Created by sure-fi on 1/23/18. + */ +class ManufacturerData( + val device_id : String, + val firmware_version: Float, + val device_state: Short, + val tx :String, + val manufacturerData: String +){ + +} \ No newline at end of file diff --git a/app/src/main/java/suer_fi/developmentkitapp/ModuleInterface.kt b/app/src/main/java/suer_fi/developmentkitapp/ModuleInterface.kt new file mode 100644 index 0000000..22677a7 --- /dev/null +++ b/app/src/main/java/suer_fi/developmentkitapp/ModuleInterface.kt @@ -0,0 +1,190 @@ +package suer_fi.developmentkitapp + +import android.bluetooth.BluetoothGatt +import android.bluetooth.BluetoothGattCallback +import android.bluetooth.BluetoothGattCharacteristic +import android.bluetooth.BluetoothProfile +import android.support.v7.app.AppCompatActivity +import android.os.Bundle +import android.support.v4.app.Fragment +import android.support.v4.app.FragmentManager +import android.view.Menu +import android.view.MenuItem +import android.view.View +import kotlinx.android.synthetic.main.activity_module_interface.* +import kotlinx.android.synthetic.main.fragment_module_interface.view.* +import org.jetbrains.anko.alert + +import android.util.Log +import android.support.v4.app.FragmentPagerAdapter +import android.support.v4.view.ViewPager +import suer_fi.developmentkitapp.R.id.scanning_div + + +class ModuleInterface : AppCompatActivity() { + + private var device: BluetoothPeripheral? = null + private var bluetoothGattCallback : BluetoothGattCallback? = null + private var bluetoothGatt : BluetoothGatt? = null + private var mainTabFragment: MainTabFragment? = null + private var secondTabFragment: SecondTabFragment? null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_module_interface) + Log.d("DEBUG","onCreate") + + initDevice() + initTabs() + +/* fab.setOnClickListener { view -> + Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) + .setAction("Action", null).show() + } +*/ + } + + private fun initTabs(){ + val pageAdapter = PageAdapter(supportFragmentManager) // getSupportFragmentManager() this method return a FragmentManager object + + pageAdapter.add(MainTabFragment.newInstance(),"Main") + pageAdapter.add(SecondTabFragment.newInstance(),"Second") + + view_pager.adapter = pageAdapter + tabs.setupWithViewPager(view_pager) // it set the tabs to the view + } + + private fun hideBarNavigation(){ + var decorView = window.decorView + val uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN + decorView.systemUiVisibility = uiOptions + } + + private fun initDevice(){ + Log.d("DEBUG","initDevice") + + device = intent.getParcelableExtra("device") + + if(device != null){ + if(device is BluetoothPeripheral){ + connectDevice() + }else{ + Log.d("DEBUG","init device fail") + } + }else{ + Log.d("DEBUG","init device fail, the device is null") + } + } + + private fun processDeviceConnected(){ + + } + + private fun connectDevice(){ + Log.d("DEBUG","connectDevice") + if(device != null){ + bluetoothGattCallback = setUpBluetoothGattCallback() + bluetoothGatt = device?.bluetooth_device?.connectGatt(this,true,bluetoothGattCallback) + }else{ + Log.w("DEBUG","The device wasn't correctly transfer to the module interface.") + } + } + + private fun connectedDevice(){ + Log.d("DEBUG","connectedDevice") + hideConnectingLayout() + } + + private fun showConnectingLayout(){ + /* runOnUiThread{ + scanning_div.visibility = View.VISIBLE + } + */ + } + + private fun hideConnectingLayout(){ + /*runOnUiThread{ + scanning_div.visibility = View.GONE + }*/ + } + + private fun disconnectedDevice(){ + Log.d("DEBUG","disconnectedDevice") + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + // Inflate the menu; this adds items to the action bar if it is present. + menuInflater.inflate(R.menu.menu_module_interface, menu) + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + val id = item.itemId + + if (id == R.id.action_settings) { + return true + } + + return super.onOptionsItemSelected(item) + } + + private fun discoverServices(){ + bluetoothGatt?.discoverServices() + } + + private fun setUpBluetoothGattCallback() : BluetoothGattCallback{ + + return object : BluetoothGattCallback (){ + + override fun onCharacteristicChanged(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?) { + super.onCharacteristicChanged(gatt, characteristic) + Log.d("DEBUG","onCharacteristicChanged") + } + + override fun onCharacteristicRead(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int) { + super.onCharacteristicRead(gatt, characteristic, status) + Log.d("DEBUG","onCharacteristicRead") + } + + override fun onCharacteristicWrite(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int) { + super.onCharacteristicWrite(gatt, characteristic, status) + Log.d("DEBUG","onConnectionStateChange") + } + + override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) { + super.onConnectionStateChange(gatt, status, newState) + Log.d("DEBUG","onConnectionStateChange status: ${status} || new_state : ${newState}") + + when(newState){ + BluetoothProfile.STATE_CONNECTED -> { + connectedDevice() + } + + BluetoothProfile.STATE_DISCONNECTED -> { + disconnectedDevice() + } + } + } + + override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) { + super.onServicesDiscovered(gatt, status) + Log.d("DEBUG","onServicesDiscovered") + if (status === BluetoothGatt.GATT_SUCCESS) { + // Set notifications on this service. + + val services = gatt?.services + + for (service in services.orEmpty()){ + Log.d("DEBUG",service.uuid.toString()) + } + } else { + Log.w("DEBUG", "onServicesDiscovered received: " + status) + } + } + } + } + +} diff --git a/app/src/main/java/suer_fi/developmentkitapp/PageAdapter.kt b/app/src/main/java/suer_fi/developmentkitapp/PageAdapter.kt new file mode 100644 index 0000000..8f64051 --- /dev/null +++ b/app/src/main/java/suer_fi/developmentkitapp/PageAdapter.kt @@ -0,0 +1,34 @@ +package suer_fi.developmentkitapp + +import android.support.v4.app.Fragment +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter + +class PageAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) { + + private val tabNames: ArrayList + val fragments: ArrayList + + init { + tabNames = ArrayList() + fragments = ArrayList() + } + + + fun add(fragment: Fragment, title: String) { + tabNames.add(title) + fragments.add(fragment) + } + + override fun getCount(): Int { + return fragments.size + } + + override fun getItem(position: Int): Fragment { + return fragments[position] + } + + override fun getPageTitle(position: Int): CharSequence { + return tabNames[position] + } +} \ No newline at end of file diff --git a/app/src/main/java/suer_fi/developmentkitapp/SecondTabFragment.kt b/app/src/main/java/suer_fi/developmentkitapp/SecondTabFragment.kt new file mode 100644 index 0000000..9863f39 --- /dev/null +++ b/app/src/main/java/suer_fi/developmentkitapp/SecondTabFragment.kt @@ -0,0 +1,32 @@ +package suer_fi.developmentkitapp + +import android.support.v4.app.Fragment +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import kotlinx.android.synthetic.main.fragment_page.* + +/** + * Created by sure-fi on 1/31/18. + */ +class SecondTabFragment : Fragment(){ + + + + companion object { + val PAGE_NUM = "PAGE_NUM" + fun newInstance(): SecondTabFragment{ + return SecondTabFragment() + } + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val view = inflater.inflate(R.layout.second_tab_fragment, container, false) + val page = getArguments().getInt(PAGE_NUM) + return view + } + + +} \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/bluetooth.png b/app/src/main/res/drawable-hdpi/bluetooth.png new file mode 100755 index 0000000..51bb2c7 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/bluetooth.png differ diff --git a/app/src/main/res/drawable-ldpi/bluetooth.png b/app/src/main/res/drawable-ldpi/bluetooth.png new file mode 100755 index 0000000..3158f06 Binary files /dev/null and b/app/src/main/res/drawable-ldpi/bluetooth.png differ diff --git a/app/src/main/res/drawable-mdpi/bluetooth.png b/app/src/main/res/drawable-mdpi/bluetooth.png new file mode 100755 index 0000000..dc96ead Binary files /dev/null and b/app/src/main/res/drawable-mdpi/bluetooth.png differ diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..c7bd21d --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable-xhdpi/bluetooth.png b/app/src/main/res/drawable-xhdpi/bluetooth.png new file mode 100755 index 0000000..da0d875 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/bluetooth.png differ diff --git a/app/src/main/res/drawable-xxhdpi/bluetooth.png b/app/src/main/res/drawable-xxhdpi/bluetooth.png new file mode 100755 index 0000000..a42e909 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/bluetooth.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/bluetooth.png b/app/src/main/res/drawable-xxxhdpi/bluetooth.png new file mode 100755 index 0000000..1d2d801 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bluetooth.png differ diff --git a/app/src/main/res/drawable/black_rectangle.xml b/app/src/main/res/drawable/black_rectangle.xml new file mode 100644 index 0000000..f901e63 --- /dev/null +++ b/app/src/main/res/drawable/black_rectangle.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/hvac_equipment_rectangle.xml b/app/src/main/res/drawable/hvac_equipment_rectangle.xml new file mode 100644 index 0000000..2cb20bb --- /dev/null +++ b/app/src/main/res/drawable/hvac_equipment_rectangle.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/hvac_thermostat_rectangle.xml b/app/src/main/res/drawable/hvac_thermostat_rectangle.xml new file mode 100644 index 0000000..52986ed --- /dev/null +++ b/app/src/main/res/drawable/hvac_thermostat_rectangle.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..d5fccc5 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/serial_data_central_rectangle.xml b/app/src/main/res/drawable/serial_data_central_rectangle.xml new file mode 100644 index 0000000..3886a87 --- /dev/null +++ b/app/src/main/res/drawable/serial_data_central_rectangle.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/serial_data_remote_rectangle.xml b/app/src/main/res/drawable/serial_data_remote_rectangle.xml new file mode 100644 index 0000000..40a25b0 --- /dev/null +++ b/app/src/main/res/drawable/serial_data_remote_rectangle.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/sure_fi_module_rectangle.xml b/app/src/main/res/drawable/sure_fi_module_rectangle.xml new file mode 100644 index 0000000..c45858a --- /dev/null +++ b/app/src/main/res/drawable/sure_fi_module_rectangle.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/uknown_rectangle.xml b/app/src/main/res/drawable/uknown_rectangle.xml new file mode 100644 index 0000000..c700399 --- /dev/null +++ b/app/src/main/res/drawable/uknown_rectangle.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/wiegand_central_rectangle.xml b/app/src/main/res/drawable/wiegand_central_rectangle.xml new file mode 100644 index 0000000..bfa8187 --- /dev/null +++ b/app/src/main/res/drawable/wiegand_central_rectangle.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/wiegand_remote_rectangle.xml b/app/src/main/res/drawable/wiegand_remote_rectangle.xml new file mode 100644 index 0000000..bf78818 --- /dev/null +++ b/app/src/main/res/drawable/wiegand_remote_rectangle.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/font/muli_extralight.xml b/app/src/main/res/font/muli_extralight.xml new file mode 100644 index 0000000..86b7109 --- /dev/null +++ b/app/src/main/res/font/muli_extralight.xml @@ -0,0 +1,7 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..9c5810a --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/app/src/main/res/layout/activity_module_interface.xml b/app/src/main/res/layout/activity_module_interface.xml new file mode 100644 index 0000000..e6c55f5 --- /dev/null +++ b/app/src/main/res/layout/activity_module_interface.xml @@ -0,0 +1,25 @@ + + + + + + + diff --git a/app/src/main/res/layout/device_list_item.xml b/app/src/main/res/layout/device_list_item.xml new file mode 100644 index 0000000..c014f43 --- /dev/null +++ b/app/src/main/res/layout/device_list_item.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_module_interface.xml b/app/src/main/res/layout/fragment_module_interface.xml new file mode 100644 index 0000000..205e181 --- /dev/null +++ b/app/src/main/res/layout/fragment_module_interface.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_page.xml b/app/src/main/res/layout/fragment_page.xml new file mode 100644 index 0000000..94a1f6e --- /dev/null +++ b/app/src/main/res/layout/fragment_page.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/main_device_activity.xml b/app/src/main/res/layout/main_device_activity.xml new file mode 100644 index 0000000..b9bebf1 --- /dev/null +++ b/app/src/main/res/layout/main_device_activity.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + +