Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
336 changes: 336 additions & 0 deletions PRIVACY_POLICY.zh-CN.md

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<img src='/metadata/en-US/images/header.png'/>

# 蓝牙雷达

<!-- <a href='https://play.google.com/store/apps/details?id=f.cking.software&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' src='https://github.com/BLE-Research-Group/MetaRadar/assets/18288554/dd3fc41a-9b51-4747-9a2c-57b37d4706aa' width='200'/></a> -->
<a href='https://github.com/BLE-Research-Group/MetaRadar/releases?q=Release+Build&expanded=true'><img alt='Get it on IzzyOnDroid' src='https://github.com/BLE-Research-Group/MetaRadar/assets/18288554/b1cb44a9-3fd4-4f83-8700-485c10b090ba' width='200'/></a>
<a href='https://f-droid.org/en/packages/f.cking.software/'><img alt='Get it on F-Droid' src='https://github.com/BLE-Research-Group/MetaRadar/assets/18288554/c03a0cf2-b39a-4344-adb8-d4cde7ce4b61' width='200'/></a>
<a href='https://android.izzysoft.de/repo/apk/f.cking.software'><img alt='Get it on IzzyOnDroid' src='https://github.com/BLE-Research-Group/MetaRadar/assets/18288554/c0c85c9f-edc8-4fc7-97b1-bda925bf0833' width='200'/></a>

> [!WARNING]
> 本项目**仅用于教育、安全研究和个人调查目的**。**作者不认可或鼓励将本软件用于任何非法或不道德的活动**。您**需自行负责**确保使用本工具时遵守所有适用的法律法规。

低功耗蓝牙(BLE)是一种广泛使用的无线协议,为您周围的各种设备提供支持——从耳机、智能手表、健身追踪器到 AirTag、物联网设备、游戏控制器,甚至现代情趣用品。BLE 设备通过广播小型数据包进行通信,其中可能包含设备标识符、元数据和其他连接所需的信息。

这些广播虽然对设备功能至关重要,但也可能被用来追踪您的存在和行动。例如,一副廉价的无线耳机可能会公开暴露一个持久标识符。任何在附近监听 BLE 数据包的人——无论是政府、公司还是恶意行为者——都可能在未经您同意的情况下利用这些信息追踪您。

幸运的是,许多现代设备在 BLE 中实现了隐私功能以防止追踪,例如随机化地址和有限广播。BLE Radar 帮助您区分保护您隐私的设备和可能被追踪的设备。通过分析您周围的 BLE 流量,应用让您了解哪些设备可以安全使用。

除了分析之外,BLE Radar 还可以实时保护您。当可疑设备在附近或某台设备随您移动一段时间时,应用可以提醒您,让您对潜在的跟踪或不必要的追踪获得早期预警。您可以根据设备标识符、类型或行为配置提醒,以满足您的安全需求。

开发这个应用的目标是让您能够了解和控制环境中的 BLE 设备。了解哪些设备正在广播可追踪信息、哪些注重隐私,能让您对日常使用、佩戴和交互的设备做出明智的决定。

应用主要功能:
* 扫描、分析和跟踪周围的蓝牙设备;
* 为雷达创建灵活的筛选条件;
* 对扫描到的 BLE 设备进行深度分析,从可用的 GATT 服务获取数据;
* GATT 服务浏览器;
* 通过元数据识别设备类型;
* 估算到设备的大致距离。

本应用不会共享您的个人数据或地理位置,所有工作均在离线状态下完成。

<img src='/metadata/en-US/images/phoneScreenshots/Screenshot_2.png' width='200'/> <img src='/metadata/en-US/images/phoneScreenshots/Screenshot_4.png' width='200'/> <img src='/metadata/en-US/images/phoneScreenshots/Screenshot_5.png' width='200'/> <img src='/metadata/en-US/images/phoneScreenshots/Screenshot_7.png' width='200'/>
11 changes: 11 additions & 0 deletions app/src/main/java/f/cking/software/data/repo/SettingsRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@ class SettingsRepository(
sharedPreferences.edit { putBoolean(KEY_WAKE_UP_SCREEN_WHILE_SCANNING, value) }
}

fun setAppLanguage(languageTag: String) {
sharedPreferences.edit { putString(KEY_APP_LANGUAGE, languageTag) }
}

fun getAppLanguage(): String {
return sharedPreferences.getString(KEY_APP_LANGUAGE, DEFAULT_APP_LANGUAGE) ?: DEFAULT_APP_LANGUAGE
}

companion object {
private const val KEY_GARBAGING_TIME = "key_garbaging_time"
private const val KEY_USE_GPS_ONLY = "key_use_gps_location_only"
Expand All @@ -154,6 +162,9 @@ class SettingsRepository(
private const val KEY_DISCLAIMER_WAS_ACCEPTED = "key_disclaimer_was_accepted"
private const val KEY_WHAT_IS_THIS_APP_FOR_WAS_SHOWN = "what_is_this_app_for_was_shown"
private const val KEY_WAKE_UP_SCREEN_WHILE_SCANNING = "key_wake_up_screen_while_scanning"
private const val KEY_APP_LANGUAGE = "key_app_language"

const val DEFAULT_APP_LANGUAGE = "system"

const val NO_APP_LAUNCH_TIME = -1L
const val NO_ENJOY_THE_APP_STARTING_POINT = -1L
Expand Down
79 changes: 79 additions & 0 deletions app/src/main/java/f/cking/software/ui/settings/SettingsScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package f.cking.software.ui.settings
import android.text.format.Formatter
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
Expand Down Expand Up @@ -32,6 +34,7 @@ import androidx.compose.ui.unit.sp
import com.vanpra.composematerialdialogs.rememberMaterialDialogState
import f.cking.software.BuildConfig
import f.cking.software.R
import f.cking.software.data.repo.SettingsRepository
import f.cking.software.dateTimeStringFormat
import f.cking.software.utils.graphic.BottomNavigationSpacer
import f.cking.software.utils.graphic.FABSpacer
Expand Down Expand Up @@ -330,6 +333,82 @@ object SettingsScreen {
viewModel.toggleWakeUpOnScreen()
}
)
LanguageSelector(viewModel = viewModel)
}
}

@Composable
private fun LanguageSelector(viewModel: SettingsViewModel) {
val dialogState = rememberMaterialDialogState()
val currentLanguageName = when (viewModel.appLanguage) {
"en" -> stringResource(R.string.language_english)
"zh-rCN" -> stringResource(R.string.language_chinese)
"hu" -> stringResource(R.string.language_hungarian)
"ru" -> stringResource(R.string.language_russian)
else -> stringResource(R.string.language_system)
}

ThemedDialog(
dialogState = dialogState,
buttons = {
negativeButton(
text = stringResource(R.string.cancel),
textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)
) { dialogState.hide() }
},
) {
Column(Modifier.padding(16.dp)) {
Text(text = stringResource(R.string.language_dialog_title), fontSize = 18.sp, fontWeight = FontWeight.Bold)
Spacer(modifier = Modifier.height(8.dp))
LanguageOption(textRes = R.string.language_system) {
viewModel.onLanguageSelected(SettingsRepository.DEFAULT_APP_LANGUAGE)
dialogState.hide()
}
LanguageOption(textRes = R.string.language_english) {
viewModel.onLanguageSelected("en")
dialogState.hide()
}
LanguageOption(textRes = R.string.language_chinese) {
viewModel.onLanguageSelected("zh-rCN")
dialogState.hide()
}
LanguageOption(textRes = R.string.language_hungarian) {
viewModel.onLanguageSelected("hu")
dialogState.hide()
}
LanguageOption(textRes = R.string.language_russian) {
viewModel.onLanguageSelected("ru")
dialogState.hide()
}
}
}

Row(
modifier = Modifier
.fillMaxWidth()
.clickable { dialogState.show() }
.padding(horizontal = 16.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Column(
modifier = Modifier.weight(1f),
) {
Text(text = stringResource(R.string.language))
Spacer(modifier = Modifier.height(4.dp))
Text(text = currentLanguageName, fontWeight = FontWeight.Light, fontSize = 12.sp)
}
}
}

@Composable
private fun LanguageOption(textRes: Int, onClick: () -> Unit) {
Box(
modifier = Modifier
.fillMaxWidth()
.clickable { onClick.invoke() }
.padding(vertical = 8.dp)
) {
Text(text = stringResource(textRes))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import android.app.Application
import android.net.Uri
import android.provider.Settings
import android.widget.Toast
import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.core.os.LocaleListCompat
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import f.cking.software.BuildConfig
Expand Down Expand Up @@ -57,6 +59,7 @@ class SettingsViewModel(
var wakeUpWhileScanning: Boolean by mutableStateOf(settingsRepository.getWakeUpScreenWhileScanning())
var silentModeEnabled: Boolean by mutableStateOf(settingsRepository.getSilentMode())
var deepAnalysisEnabled: Boolean by mutableStateOf(settingsRepository.getEnableDeepAnalysis())
var appLanguage: String by mutableStateOf(settingsRepository.getAppLanguage())

val databaseInfo by getDatabaseInfoInteractor.execute().collectAsState(viewModelScope, null)

Expand Down Expand Up @@ -162,6 +165,17 @@ class SettingsViewModel(
settingsRepository.setSilentMode(!settingsRepository.getSilentMode())
}

fun onLanguageSelected(languageTag: String) {
settingsRepository.setAppLanguage(languageTag)
appLanguage = languageTag
val localeList = if (languageTag == SettingsRepository.DEFAULT_APP_LANGUAGE) {
LocaleListCompat.getEmptyLocaleList()
} else {
LocaleListCompat.forLanguageTags(languageTag)
}
AppCompatDelegate.setApplicationLocales(localeList)
}

fun onReportIssueClick() {
intentHelper.openUrl(BuildConfig.REPORT_ISSUE_URL)
}
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/res/values-hu/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,11 @@
<string name="turn_on">Bekapcsolás</string>
<string name="unknown_capital_case">ISMERETLEN</string>
<string name="lifetime_data_last_update">örök: %1$s | legutóbbi frissítés: %2$s ideje</string>
<string name="language">Nyelv</string>
<string name="language_dialog_title">Alkalmazás nyelve</string>
<string name="language_system">Rendszer szerint</string>
<string name="language_english">English</string>
<string name="language_chinese">中文</string>
<string name="language_hungarian">Magyar</string>
<string name="language_russian">Русский</string>
</resources>
7 changes: 7 additions & 0 deletions app/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@
<string name="silent_mode_subtitle">Выключить любую сетевую коммуникацию от приложения. Может быть полезно чтобы экономить трафик или оставаться незаметным в сети.</string>
<string name="database_actions">Управление базой данных</string>
<string name="app_settings_title">Настройки</string>
<string name="language">Язык</string>
<string name="language_dialog_title">Язык приложения</string>
<string name="language_system">Как в системе</string>
<string name="language_english">English</string>
<string name="language_chinese">中文</string>
<string name="language_hungarian">Magyar</string>
<string name="language_russian">Русский</string>
<string name="silent_mode_is_off_toast">Оффлайн режим выключен. Вы можете включить его в настройках.</string>
<string name="select_manufacturer">Поиск производителя</string>

Expand Down
Loading