diff --git a/README.md b/README.md
index 08c27fb..6629765 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,26 @@
-
# :cyclone: Android Beacon Scanner #
-A simple android beacon scanner that can recognize iBeacons, AltBeacons, Eddystone beacons (UID and URL, with or without TLM) and RuuviTags [available on Google Play](https://play.google.com/store/apps/details?id=com.bridou_n.beaconscanner).
+Forked from "A simple [android beacon scanner](https://github.com/Bridouille/android-beacon-scanner) that can recognize iBeacons, AltBeacons, Eddystone beacons (UID and URL, with or without TLM) and RuuviTags [available on Google Play](https://play.google.com/store/apps/details?id=com.bridou_n.beaconscanner)."
-
+
+## :key: Modified features ##
+The forked project has the following new features:
+
+* White list: white can help doing experiment without manualy blocking a lot of beacons; (this is helpful if there are a lot of beacons in the experiment enviroment);
+* (TODO): dump the db to local csv files;
Available for android 5.0+ and smartphones with Bluetooth LE.
+* Original app visualization:
+
+
+
+* White list part: (new feature, under developing)
+
+
+
+
+
## :key: Features ##
This app will scan for beacons near you! :v:
diff --git a/app/build.gradle b/app/build.gradle
index ccc212f..7773c8f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -18,21 +18,21 @@ android {
multiDexEnabled true
}
- signingConfigs {
- release {
- keyAlias 'BeaconScannerKey'
- keyPassword beacon_scanner_key_password
- storeFile file(beacon_scanner_store_file)
- storePassword beacon_scanner_store_password
- }
- }
+// signingConfigs {
+// release {
+// keyAlias 'BeaconScannerKey'
+//// keyPassword beacon_scanner_key_password
+// storeFile file(beacon_scanner_store_file)
+// storePassword beacon_scanner_store_password
+// }
+// }
buildTypes {
release {
minifyEnabled true
resValue "string", "app_name", "Beacon Scanner"
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- signingConfig signingConfigs.release
+// signingConfig signingConfigs.release
}
debug {
diff --git a/app/src/main/java/com/bridou_n/beaconscanner/Database/BeaconsDao.kt b/app/src/main/java/com/bridou_n/beaconscanner/Database/BeaconsDao.kt
index d271e66..6724e10 100644
--- a/app/src/main/java/com/bridou_n/beaconscanner/Database/BeaconsDao.kt
+++ b/app/src/main/java/com/bridou_n/beaconscanner/Database/BeaconsDao.kt
@@ -19,6 +19,10 @@ interface BeaconsDao {
@Query("SELECT * FROM $TABLE_NAME WHERE is_blocked = :blocked")
fun getBeacons(blocked: Boolean = false) : Flowable>
+
+ @Query("SELECT * FROM $TABLE_NAME WHERE is_white = :whited")
+ fun getWhiteBeacons(whited: Boolean = true) : Flowable>
+
@Query("SELECT * FROM $TABLE_NAME WHERE hashcode = :hashcode")
fun getBeaconById(hashcode: Int) : Single
@@ -28,6 +32,9 @@ interface BeaconsDao {
@Insert(onConflict = REPLACE)
fun insertBeacon(beacon: BeaconSaved)
+// @Update("")
+// fun update
+
@Delete
fun deleteBeacon(beacon: BeaconSaved)
diff --git a/app/src/main/java/com/bridou_n/beaconscanner/dagger/AppComponent.kt b/app/src/main/java/com/bridou_n/beaconscanner/dagger/AppComponent.kt
index 8275811..3865e7d 100644
--- a/app/src/main/java/com/bridou_n/beaconscanner/dagger/AppComponent.kt
+++ b/app/src/main/java/com/bridou_n/beaconscanner/dagger/AppComponent.kt
@@ -28,6 +28,5 @@ interface AppComponent {
fun inject(activity: BeaconListActivity)
fun inject(activity: SettingsActivity)
fun inject(activity: BlockedActivity)
-
fun inject(bs: ControlsBottomSheetDialog)
}
diff --git a/app/src/main/java/com/bridou_n/beaconscanner/features/beaconList/BeaconListActivity.kt b/app/src/main/java/com/bridou_n/beaconscanner/features/beaconList/BeaconListActivity.kt
index ff0ebf0..6bac521 100644
--- a/app/src/main/java/com/bridou_n/beaconscanner/features/beaconList/BeaconListActivity.kt
+++ b/app/src/main/java/com/bridou_n/beaconscanner/features/beaconList/BeaconListActivity.kt
@@ -41,6 +41,7 @@ import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.activity_main.*
+import kotlinx.android.synthetic.main.bottom_sheet_controls.*
import org.altbeacon.beacon.Beacon
import org.altbeacon.beacon.BeaconConsumer
import org.altbeacon.beacon.BeaconManager
@@ -48,6 +49,7 @@ import org.altbeacon.beacon.Region
import timber.log.Timber
import java.util.*
import javax.inject.Inject
+import kotlin.collections.ArrayList
class BeaconListActivity : AppCompatActivity(), BeaconConsumer {
@@ -83,9 +85,11 @@ class BeaconListActivity : AppCompatActivity(), BeaconConsumer {
private var loggingRequests = CompositeDisposable()
private var isScanning = false
+
+ private var isWhiting = false
private val rvAdapter = BeaconsRecyclerViewAdapter { beacon ->
- ControlsBottomSheetDialog.newInstance(beacon.hashcode).apply {
+ ControlsBottomSheetDialog.newInstance(beacon.hashcode,false,beacon.isWhite).apply {
show(supportFragmentManager)
}
}
@@ -109,6 +113,10 @@ class BeaconListActivity : AppCompatActivity(), BeaconConsumer {
scan_fab.setOnClickListener {
toggleScan()
}
+
+ white_fab.setOnClickListener({
+ toogleWhite()
+ })
}
private fun toggleScan() {
@@ -148,8 +156,25 @@ class BeaconListActivity : AppCompatActivity(), BeaconConsumer {
keepScreenOn(false)
isScanning = false
}
+
+
+ private fun toogleWhite(){
+ val ori_name = getString(if (isScanning()) R.string.scanning_for_beacons else R.string.app_name)
+ if (!isWhiting()){
+ tracker.logEvent("start_whiting_clicked",null)
+ isWhiting = true
+ toolbar.title = ori_name + " (whitelist)"
+ }
+ else{
+ isWhiting = false
+ toolbar.title = ori_name
+ }
+ white_fab.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, if (isWhiting) R.color.colorPauseFab else R.color.colorSecondary))
+ }
fun isScanning() = isScanning
+
+ fun isWhiting() = isWhiting
private fun unbindBeaconManager() {
if (beaconManager?.isBound(this) == true) {
@@ -192,14 +217,29 @@ class BeaconListActivity : AppCompatActivity(), BeaconConsumer {
beaconManager = component().providesBeaconManager()
observeBluetoothState()
- listQuery = db.beaconsDao().getBeacons(blocked = false)
- .subscribeOn(Schedulers.io())
- .map { list ->
- if (list.isEmpty()) {
- listOf(BeaconRow.EmptyState)
- } else {
- list.map { BeaconRow.Beacon(it) }
+
+// val listQuery = db.beaconsDao()
+ // here not possible to change the white setting:
+
+ listQuery = db.beaconsDao().getBeacons(blocked = false).subscribeOn(Schedulers.io())
+ .map { list ->
+ if(!isWhiting){
+ if (list.isEmpty()) {
+ listOf(BeaconRow.EmptyState)
+ } else {
+ list.map { when(it.isWhite){
+ true -> BeaconRow.BeaconWhite(it)
+ else -> BeaconRow.Beacon(it)
+ } }
+ }
+ }else{
+ if (list.filter{it.isWhite}.isEmpty()) {
+ listOf(BeaconRow.EmptyState)
+ } else {
+ list.filter{it.isWhite}.map { BeaconRow.BeaconWhite(it) }
+ }
}
+
}
.doOnSubscribe { rvAdapter.submitList(listOf(BeaconRow.Loading)) }
.observeOn(AndroidSchedulers.mainThread())
@@ -283,8 +323,8 @@ class BeaconListActivity : AppCompatActivity(), BeaconConsumer {
} catch (e: EmptyResultSetException) {
null
}
-
- BeaconSaved.createFromBeacon(it, isBlocked = beaconInDb?.isBlocked ?: false)
+ Timber.d(it.toString())
+ BeaconSaved.createFromBeacon(it, isBlocked = beaconInDb?.isBlocked ?: false, isWhite= beaconInDb?.isWhite?:false)
}
.doOnNext {
db.beaconsDao().insertBeacon(it)
@@ -419,6 +459,11 @@ class BeaconListActivity : AppCompatActivity(), BeaconConsumer {
tracker.log("action_settings")
startActivity(Intent(this, SettingsActivity::class.java))
}
+
+ R.id.action_save -> {
+ tracker.log("white_lists")
+ }
+
else -> return super.onOptionsItemSelected(item)
}
return true
diff --git a/app/src/main/java/com/bridou_n/beaconscanner/features/beaconList/BeaconsRVAdapter.kt b/app/src/main/java/com/bridou_n/beaconscanner/features/beaconList/BeaconsRVAdapter.kt
index 1dfad5e..b85b9b3 100644
--- a/app/src/main/java/com/bridou_n/beaconscanner/features/beaconList/BeaconsRVAdapter.kt
+++ b/app/src/main/java/com/bridou_n/beaconscanner/features/beaconList/BeaconsRVAdapter.kt
@@ -22,6 +22,7 @@ import com.google.android.flexbox.FlexDirection
import com.google.android.flexbox.FlexboxLayoutManager
import com.google.android.flexbox.JustifyContent
import kotlinx.android.synthetic.main.item_beacon.view.*
+import timber.log.Timber
import java.util.*
/**
@@ -41,6 +42,15 @@ class BeaconsRecyclerViewAdapter(
is BeaconRow.Beacon -> {
when (newItem) {
is BeaconRow.Beacon -> oldItem.beacon.hashcode == newItem.beacon.hashcode
+ is BeaconRow.BeaconWhite -> oldItem.beacon.hashcode == newItem.beacon.hashcode
+ else -> false
+ }
+ }
+
+ is BeaconRow.BeaconWhite -> {
+ when (newItem) {
+ is BeaconRow.Beacon -> oldItem.beacon.hashcode == newItem.beacon.hashcode
+ is BeaconRow.BeaconWhite -> oldItem.beacon.hashcode == newItem.beacon.hashcode
else -> false
}
}
@@ -52,6 +62,14 @@ class BeaconsRecyclerViewAdapter(
return when (oldItem) {
is BeaconRow.Beacon -> {
when (newItem) {
+ is BeaconRow.Beacon -> oldItem.beacon == newItem.beacon
+ is BeaconRow.BeaconWhite -> oldItem.beacon == newItem.beacon
+ else -> false
+ }
+ }
+ is BeaconRow.BeaconWhite -> {
+ when (newItem) {
+ is BeaconRow.BeaconWhite -> oldItem.beacon == newItem.beacon
is BeaconRow.Beacon -> oldItem.beacon == newItem.beacon
else -> false
}
@@ -67,14 +85,110 @@ class BeaconsRecyclerViewAdapter(
private val beaconInfosAdapter = BeaconInfosRvAdapter()
- @SuppressLint("StringFormatMatches")
+ @SuppressLint("StringFormatMatches", "ResourceAsColor")
fun bindView(beacon: BeaconSaved) {
val ctx = itemView.context
itemView.beacon_actions.setOnClickListener {
true.also { listener?.invoke(beacon) }
}
-
+
+// itemView
+
+ itemView.beacon_type.text = ctx.getString(when (beacon.beaconType) {
+ TYPE_ALTBEACON -> R.string.altbeacon
+ TYPE_EDDYSTONE_UID -> R.string.eddystone_uid
+ TYPE_EDDYSTONE_URL -> R.string.eddystone_url
+ TYPE_RUUVITAG -> R.string.ruuvitag
+ else -> R.string.ibeacon
+ })
+ itemView.distance.text = String.format(Locale.getDefault(), "%.2f", beacon.distance)
+
+ itemView.address.text = beacon.beaconAddress
+ itemView.manufacturer.text = String.format(Locale.getDefault(), "0x%04X", beacon.manufacturer)
+ itemView.last_seen.text = DateUtils.getRelativeTimeSpanString(
+ beacon.lastSeen, Date().time,
+ DateUtils.SECOND_IN_MILLIS,
+ DateUtils.FORMAT_ABBREV_RELATIVE
+ ).toString()
+
+ val beaconInfos = mutableListOf().apply {
+ // Adding iBeacon or AltBeacon data
+ beacon.ibeaconData?.let {
+ add(BeaconInfo(ctx.getString(R.string.uuid), it.uuid))
+ add(BeaconInfo(ctx.getString(R.string.major), it.major))
+ add(BeaconInfo(ctx.getString(R.string.minor), it.minor))
+ }
+
+ add(BeaconInfo(ctx.getString(R.string.RSSI_title), String.format(ctx.getString(R.string.x_dbm), beacon.rssi)))
+ add(BeaconInfo(ctx.getString(R.string.TX_title), String.format(ctx.getString(R.string.x_dbm), beacon.txPower)))
+
+ // Adding Eddystone UID data
+ beacon.eddystoneUidData?.let {
+ add(BeaconInfo(ctx.getString(R.string.namespace_id_title), it.namespaceId))
+ add(BeaconInfo(ctx.getString(R.string.instance_id_title), it.instanceId))
+ }
+
+ // Adding Eddystone URL data
+ beacon.eddystoneUrlData?.let {
+ add(BeaconInfo(
+ title = ctx.getString(R.string.url_title),
+ content = it.url ?: "UNKNOWN",
+ onItemClicked = { onUrlClicked(it.url) }
+ ))
+ }
+
+ // Adding RuuviTag data
+ beacon.ruuviData?.let {
+ add(BeaconInfo(ctx.getString(R.string.air_pressure_title), String.format(ctx.getString(R.string.x_hpa), it.airPressure)))
+ add(BeaconInfo(ctx.getString(R.string.temperature_title), ctx.getString(R.string.x_degrees, "${it.temperatue}")))
+ add(BeaconInfo(ctx.getString(R.string.humidity_title), String.format("%d %%", it.humidity)))
+ }
+
+ // Adding TLM data
+ beacon.telemetryData?.let {
+ add(BeaconInfo(ctx.getString(R.string.battery_title), String.format(ctx.getString(R.string.x_mv), it.batteryMilliVolts)))
+ add(BeaconInfo(ctx.getString(R.string.temperature_title), ctx.getString(R.string.x_degrees, String.format("%.1f", it.temperature)))) // %.1f
+
+ add(BeaconInfo(ctx.getString(R.string.uptime_title), String.format(ctx.getString(R.string.x_seconds), it.uptime.toCoolFormat())))
+ add(BeaconInfo(ctx.getString(R.string.pdu_title), it.pduCount.toCoolFormat()))
+ }
+ }
+
+ itemView.infos_rv.apply {
+ layoutManager = FlexboxLayoutManager(context).apply {
+ flexDirection = FlexDirection.ROW
+ justifyContent = JustifyContent.SPACE_BETWEEN
+ }
+ adapter = beaconInfosAdapter
+ isNestedScrollingEnabled = false
+ }
+ beaconInfosAdapter.submitList(beaconInfos)
+ }
+
+ fun onUrlClicked(url: String?) {
+ url ?: return
+
+ try {
+ val uri = Uri.parse(url)
+ itemView.context.startActivity(Intent(Intent.ACTION_VIEW, uri))
+ } catch (e: Exception) { }
+ }
+ }
+ class BeaconWhiteViewHolder(itemView: View, val listener: OnControlsOpen?) : RecyclerView.ViewHolder(itemView) {
+
+ private val beaconInfosAdapter = BeaconInfosRvAdapter()
+
+ @SuppressLint("StringFormatMatches", "ResourceAsColor")
+ fun bindView(beacon: BeaconSaved) {
+ val ctx = itemView.context
+
+ itemView.beacon_actions.setOnClickListener {
+ true.also { listener?.invoke(beacon) }
+ }
+
+// itemView
+
itemView.beacon_type.text = ctx.getString(when (beacon.beaconType) {
TYPE_ALTBEACON -> R.string.altbeacon
TYPE_EDDYSTONE_UID -> R.string.eddystone_uid
@@ -155,7 +269,6 @@ class BeaconsRecyclerViewAdapter(
} catch (e: Exception) { }
}
}
-
class EmptyStateViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
class LoadingViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
@@ -164,6 +277,8 @@ class BeaconsRecyclerViewAdapter(
return when (viewType) {
R.layout.item_beacon -> BeaconViewHolder(view, clickListener)
+// R.layout.item_beacon_white
+ R.layout.item_beacon_white -> BeaconWhiteViewHolder(view,clickListener)
R.layout.item_beacon_empty -> EmptyStateViewHolder(view)
R.layout.item_loading -> LoadingViewHolder(view)
else -> LoadingViewHolder(view) // Should never happen
@@ -175,15 +290,21 @@ class BeaconsRecyclerViewAdapter(
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is BeaconViewHolder -> {
+ Timber.d("beacon view holder")
val beacon = (getItem(position) as BeaconRow.Beacon).beacon
holder.bindView(beacon)
}
+ is BeaconWhiteViewHolder -> {
+ val beacon = (getItem(position) as BeaconRow.BeaconWhite).beacon
+ holder.bindView(beacon)
+ }
}
}
}
-sealed class BeaconRow(@LayoutRes val layoutRes: Int) {
+sealed class BeaconRow(@LayoutRes val layoutRes: Int,val isWhite: Boolean = false) {
data class Beacon(val beacon: BeaconSaved) : BeaconRow(R.layout.item_beacon)
- object EmptyState : BeaconRow(R.layout.item_beacon_empty)
- object Loading : BeaconRow(R.layout.item_loading)
+ data class BeaconWhite(val beacon: BeaconSaved) : BeaconRow(R.layout.item_beacon_white,true)
+ object EmptyState : BeaconRow(R.layout.item_beacon_empty,false)
+ object Loading : BeaconRow(R.layout.item_loading,false)
}
diff --git a/app/src/main/java/com/bridou_n/beaconscanner/features/beaconList/ControlsBottomSheetDialog.kt b/app/src/main/java/com/bridou_n/beaconscanner/features/beaconList/ControlsBottomSheetDialog.kt
index 0f9ebd8..c61a4c0 100644
--- a/app/src/main/java/com/bridou_n/beaconscanner/features/beaconList/ControlsBottomSheetDialog.kt
+++ b/app/src/main/java/com/bridou_n/beaconscanner/features/beaconList/ControlsBottomSheetDialog.kt
@@ -7,18 +7,21 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.bridou_n.beaconscanner.AppSingleton
import com.bridou_n.beaconscanner.Database.AppDatabase
import com.bridou_n.beaconscanner.R
+import com.bridou_n.beaconscanner.models.BeaconSaved
import com.bridou_n.beaconscanner.utils.dialogs.RoundedBottomSheetDialog
import com.bridou_n.beaconscanner.utils.extensionFunctions.showSnackBar
import io.reactivex.Completable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
+import timber.log.Timber
import javax.inject.Inject
@@ -31,12 +34,14 @@ class ControlsBottomSheetDialog : RoundedBottomSheetDialog() {
companion object {
const val KEY_BEACON_ID = "key_beacon_id"
const val KEY_BLOCKED = "key_blocked"
+ const val KEY_WHITE = "key_white"
- fun newInstance(beaconId: Int, blocked: Boolean = false) : ControlsBottomSheetDialog {
+ fun newInstance(beaconId: Int, blocked: Boolean = false, white:Boolean = false) : ControlsBottomSheetDialog {
return ControlsBottomSheetDialog().apply {
arguments = Bundle().apply {
putInt(KEY_BEACON_ID, beaconId)
putBoolean(KEY_BLOCKED, blocked)
+ putBoolean(KEY_WHITE,white)
}
}
}
@@ -45,6 +50,8 @@ class ControlsBottomSheetDialog : RoundedBottomSheetDialog() {
private var beaconId: Int = 0
private var isBlockedLst: Boolean = false
+ private var isWhiteLst: Boolean = false
+
private val queries = CompositeDisposable()
@Inject lateinit var db: AppDatabase
@@ -53,6 +60,7 @@ class ControlsBottomSheetDialog : RoundedBottomSheetDialog() {
if (bundle != null) {
beaconId = bundle.getInt(KEY_BEACON_ID)
isBlockedLst = bundle.getBoolean(KEY_BLOCKED)
+ isWhiteLst = bundle.getBoolean(KEY_WHITE)
}
}
@@ -60,6 +68,7 @@ class ControlsBottomSheetDialog : RoundedBottomSheetDialog() {
super.onSaveInstanceState(outState)
outState.putInt(KEY_BEACON_ID, beaconId)
outState.putBoolean(KEY_BLOCKED, isBlockedLst)
+ outState.putBoolean(KEY_BLOCKED,isWhiteLst)
}
override fun onCreate(savedInstanceState: Bundle?) {
@@ -82,11 +91,20 @@ class ControlsBottomSheetDialog : RoundedBottomSheetDialog() {
val blockedContainer = contentView.findViewById(R.id.block)
val blockLabel = contentView.findViewById(R.id.block_label)
+ val whiteContainer = contentView.findViewById(R.id.white)
+ val whiteLabel = contentView.findViewById(R.id.white_label)
+ val whiteIcon = contentView.findViewById(R.id.fileimage)
+
if (isBlockedLst) {
removeContainer.visibility = View.GONE
blockLabel.setText(R.string.unblock)
}
+ if(isWhiteLst){
+ whiteLabel.setText(R.string.exclude)
+ whiteIcon.setImageResource(R.drawable.ic_round_delete_24px)
+ }
+
removeContainer.setOnClickListener {
queries.add(Completable.fromCallable {
db.beaconsDao().deleteBeaconById(beaconId)
@@ -96,6 +114,7 @@ class ControlsBottomSheetDialog : RoundedBottomSheetDialog() {
}
clipboardContainer.setOnClickListener {
+ Timber.d("click clipboard")
context?.let { ctx ->
queries.add(
db.beaconsDao().getBeaconById(beaconId)
@@ -105,7 +124,6 @@ class ControlsBottomSheetDialog : RoundedBottomSheetDialog() {
val clipboard = ctx.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("Beacon infos", it.toJson())
clipboard.primaryClip = clip
-
dismissAllowingStateLoss()
(activity as? BeaconListActivity)?.showGenericError(ctx.getString(R.string.the_informations_has_been_copied)) ?:
(activity as? AppCompatActivity)?.showSnackBar(ctx.getString(R.string.the_informations_has_been_copied))
@@ -129,6 +147,20 @@ class ControlsBottomSheetDialog : RoundedBottomSheetDialog() {
dismissAllowingStateLoss()
})
}
+
+ whiteContainer.setOnClickListener{
+ Timber.d("click white")
+ queries.add(db.beaconsDao().getBeaconById(beaconId).flatMapCompletable {
+ Completable.fromCallable{
+ db.beaconsDao().insertBeacon(it.copy(isWhite=!isWhiteLst))
+ }
+ }.subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe {
+ dismissAllowingStateLoss()
+ })
+
+ }
}
override fun onDestroy() {
diff --git a/app/src/main/java/com/bridou_n/beaconscanner/features/settings/SettingsActivity.kt b/app/src/main/java/com/bridou_n/beaconscanner/features/settings/SettingsActivity.kt
index 9fdf5fb..b22478d 100644
--- a/app/src/main/java/com/bridou_n/beaconscanner/features/settings/SettingsActivity.kt
+++ b/app/src/main/java/com/bridou_n/beaconscanner/features/settings/SettingsActivity.kt
@@ -14,7 +14,7 @@ import com.afollestad.materialdialogs.actions.getActionButton
import com.afollestad.materialdialogs.input.getInputField
import com.afollestad.materialdialogs.input.input
import com.afollestad.materialdialogs.list.listItemsSingleChoice
-import com.bridou_n.beaconscanner.BuildConfig
+//import com.bridou_n.beaconscanner.BuildConfig
import com.bridou_n.beaconscanner.R
import com.bridou_n.beaconscanner.features.blockedList.BlockedActivity
import com.bridou_n.beaconscanner.utils.PreferencesHelper
@@ -52,7 +52,7 @@ class SettingsActivity : AppCompatActivity() {
handleLoggingState(prefs.isLoggingEnabled)
toolbar_title.text = getString(R.string.settings)
- app_version.text = String.format("v%s", BuildConfig.VERSION_NAME)
+// app_version.text = String.format("v%s", BuildConfig.VERSION_NAME)
content.apply {
viewTreeObserver.addOnScrollChangedListener {
diff --git a/app/src/main/java/com/bridou_n/beaconscanner/models/BeaconSaved.kt b/app/src/main/java/com/bridou_n/beaconscanner/models/BeaconSaved.kt
index 2dc2a2a..818720f 100644
--- a/app/src/main/java/com/bridou_n/beaconscanner/models/BeaconSaved.kt
+++ b/app/src/main/java/com/bridou_n/beaconscanner/models/BeaconSaved.kt
@@ -81,7 +81,11 @@ data class BeaconSaved(
val ruuviData: RuuviData? = null,
@ColumnInfo(name = "is_blocked")
- val isBlocked: Boolean = false
+ val isBlocked: Boolean = false,
+
+ @ColumnInfo(name="is_white")
+ val isWhite: Boolean = false
+
) {
companion object {
const val TYPE_EDDYSTONE_UID = "eddystone_uid"
@@ -90,7 +94,7 @@ data class BeaconSaved(
const val TYPE_IBEACON = "ibeacon"
const val TYPE_RUUVITAG = "ruuvitag"
- fun createFromBeacon(beacon: Beacon, isBlocked: Boolean = false) : BeaconSaved {
+ fun createFromBeacon(beacon: Beacon, isBlocked: Boolean = false, isWhite: Boolean = false) : BeaconSaved {
// Common fields to every beacons
var hashcode = beacon.hashCode()
val lastSeen = Date().time
@@ -162,8 +166,8 @@ data class BeaconSaved(
eddystoneUidData = eddystoneUidData,
telemetryData = telemetryData,
ruuviData = ruuviData,
-
- isBlocked = isBlocked
+ isBlocked = isBlocked,
+ isWhite = isWhite
)
}
diff --git a/app/src/main/res/drawable/file_icon.xml b/app/src/main/res/drawable/file_icon.xml
new file mode 100644
index 0000000..724e9d2
--- /dev/null
+++ b/app/src/main/res/drawable/file_icon.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 3d06cca..a0b5dc3 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -64,6 +64,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/progress_2"
+ android:layout_marginTop="-5dp"
android:clipToPadding="false"
android:overScrollMode="never"
android:paddingTop="8dp"
@@ -71,7 +72,7 @@
android:scrollbars="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
-
+
+
+
diff --git a/app/src/main/res/layout/bottom_sheet_controls.xml b/app/src/main/res/layout/bottom_sheet_controls.xml
index 280faaf..d60a7d6 100644
--- a/app/src/main/res/layout/bottom_sheet_controls.xml
+++ b/app/src/main/res/layout/bottom_sheet_controls.xml
@@ -18,6 +18,7 @@
android:padding="16dp">
-
+
-
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_beacon.xml b/app/src/main/res/layout/item_beacon.xml
index b069037..a586df4 100644
--- a/app/src/main/res/layout/item_beacon.xml
+++ b/app/src/main/res/layout/item_beacon.xml
@@ -154,15 +154,15 @@
+ android:overScrollMode="never"
+ android:paddingBottom="16dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.0"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/header_divider" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_beacon_white.xml b/app/src/main/res/layout/item_beacon_white.xml
new file mode 100644
index 0000000..2b4fa69
--- /dev/null
+++ b/app/src/main/res/layout/item_beacon_white.xml
@@ -0,0 +1,169 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/main_menu.xml b/app/src/main/res/menu/main_menu.xml
index 09d87aa..d61d377 100644
--- a/app/src/main/res/menu/main_menu.xml
+++ b/app/src/main/res/menu/main_menu.xml
@@ -4,6 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".features.beaconList.BeaconListActivity">
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 0f68519..fbdd937 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -21,6 +21,7 @@
#FFF
+ #FF0
@color/colorBackground
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 25c64d1..4ba5cc1 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -78,12 +78,16 @@
Remove from the list
Copy infos to clipboard
Add to the blocked list
+ Add to the white list
The informations have been copied to the clipboard!
Blacklist
See the blocked beacons
No beacon has been blocked yet!
Unblock
+ Remove from white list
Open source
This app is open source! Want to see how it works under the hood or customize it to fits your needs?
While scanning, the device won\'t be put in sleep mode
+ Show beacons in white list
+ Save Scanned BLE to csv
diff --git a/build.gradle b/build.gradle
index b650cf1..d1d8c2c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -15,7 +15,7 @@ buildscript {
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
- classpath 'com.google.gms:google-services:4.3.3'
+ classpath 'com.google.gms:google-services:4.3.5'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
diff --git a/screenshots/white_list_vis_1.png b/screenshots/white_list_vis_1.png
new file mode 100644
index 0000000..050e587
Binary files /dev/null and b/screenshots/white_list_vis_1.png differ
diff --git a/screenshots/white_list_vis_2.png b/screenshots/white_list_vis_2.png
new file mode 100644
index 0000000..d727808
Binary files /dev/null and b/screenshots/white_list_vis_2.png differ