diff --git a/README.md b/README.md index 4923f71..5bcb4a7 100644 --- a/README.md +++ b/README.md @@ -83,24 +83,24 @@ In the “Add App” screen: 1. Add the following URL: https://weforge.xyz/partisan/Pulse 2. In **Override Source**, select **Forgejo (Codeberg)** -3. Tap the “Add” button at the very top, and you're done! +3. Tap the “Add” button at the very top, and you’re done! ## Install directly Go to the [Releases page](https://weforge.xyz/partisan/Pulse/releases) and download the latest file with the following format: `app-release.apk`. -Install it, and you're done! +Install it, and you’re done! _Please note that when installing directly, the app will not receive automatic updates._ # Permissions -- `ACCESS_NETWORK_STATE` - check connectivity -- `CALL_PHONE` - make a call via messenger -- `READ_CONTACTS` - check if contact has a messenger -- `READ_PHONE_NUMBERS` - detect outgoing call -- `SYSTEM_ALERT_WINDOW` - show redirecting popup and launch from background -- `INTERNET` - check connectivity and verify donates +- `ACCESS_NETWORK_STATE` – check connectivity +- `CALL_PHONE` – make a call via messenger +- `READ_CONTACTS` – check if contact has a messenger +- `READ_PHONE_NUMBERS` – detect outgoing call +- `SYSTEM_ALERT_WINDOW` – show redirecting popup and launch from background +- `INTERNET` – check connectivity and verify donates Currently all of the permissions are required. diff --git a/app/build.gradle b/app/build.gradle index d0bc59d..7b72933 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ android { applicationId = "partisan.weforge.xyz.pulse" minSdk = 29 targetSdk = 34 - versionCode = 17 - versionName = "2.0.3" + versionCode = 16 + versionName = "2.0.2" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/partisan/weforge/xyz/pulse/CallRedirectionService.kt b/app/src/main/java/partisan/weforge/xyz/pulse/CallRedirectionService.kt index 66666f6..5eae072 100644 --- a/app/src/main/java/partisan/weforge/xyz/pulse/CallRedirectionService.kt +++ b/app/src/main/java/partisan/weforge/xyz/pulse/CallRedirectionService.kt @@ -61,9 +61,7 @@ class CallRedirectionService : CallRedirectionService() { initialPhoneAccount: PhoneAccountHandle, allowInteractiveResponse: Boolean, ) { - val phoneNumber = handle.schemeSpecificPart - val numberAlias = getAnonymizedAlias(phoneNumber) - Log.d("Redirection", "onPlaceCall triggered: alias=$numberAlias, interactive=$allowInteractiveResponse") + Log.d("Redirection", "onPlaceCall triggered: uri=$handle, interactive=$allowInteractiveResponse") val capabilities = connectivityManager ?.getNetworkCapabilities(connectivityManager?.activeNetwork) @@ -96,30 +94,37 @@ class CallRedirectionService : CallRedirectionService() { return } + if (!allowInteractiveResponse) { + Log.d("Redirection", "Aborting: interactive response not allowed by system") + placeCallUnmodified() + return + } + if (prefs.redirectIfRoaming && !isOutsideHomeCountry()) { Log.d("Redirection", "Aborting: redirect only while roaming, but we're inside home country") placeCallUnmodified() return } + val phoneNumber = handle.schemeSpecificPart + Log.d("Redirection", "Resolved phone number: $phoneNumber") + if (prefs.redirectInternationalOnly && !isInternationalNumber(phoneNumber)) { - Log.d("Redirection", "Aborting: number $numberAlias is not international and pref requires it") + Log.d("Redirection", "Aborting: number is not international and pref requires it") placeCallUnmodified() return } if (prefs.isBlacklistEnabled && !prefs.isContactWhitelisted(phoneNumber)) { - Log.d("Redirection", "Aborting: number $numberAlias is not in whitelist while blacklist is enabled") + Log.d("Redirection", "Aborting: number is not in whitelist while blacklist is enabled") placeCallUnmodified() return } - - Log.d("Redirection", "Number $numberAlias is not in filters, processing redirection...") val records: Array try { records = getRecordsFromPhoneNumber(phoneNumber) - Log.d("Redirection", "Found ${records.size} raw redirect apps for number $numberAlias") + Log.d("Redirection", "Found ${records.size} raw records for contact") } catch (exc: SecurityException) { Log.w("Redirection", "SecurityException during record fetch", exc) placeCallUnmodified() @@ -130,20 +135,18 @@ class CallRedirectionService : CallRedirectionService() { .filter { prefs.isServiceEnabled(it.mimetype) } .sortedBy { prefs.getServicePriority(it.mimetype) } - Log.d("Redirection", "Filtered to ${enabledRecords.size} enabled redirect apps") + Log.d("Redirection", "Filtered to ${enabledRecords.size} enabled records") val record = enabledRecords.firstOrNull() if (record == null) { - Log.d("Redirection", "Aborting: no suitable redirect apps found for number $numberAlias") + Log.d("Redirection", "Aborting: no suitable record found for redirection") placeCallUnmodified() return } Log.d("Redirection", "Redirecting call to: ${record.mimetype} → ${record.uri}") - Log.d("Redirection", "Popup ${if (allowInteractiveResponse) "allowed" else "not allowed"} by system; ${if (prefs.popupEnabled) "enabled" else "disabled"} in prefs") - - if (allowInteractiveResponse && prefs.popupEnabled) { + if (prefs.popupEnabled) { window.show(record.uri, MIMETYPE_TO_DST_NAME[record.mimetype] ?: return) } else { window.call(record.uri) @@ -200,33 +203,6 @@ class CallRedirectionService : CallRedirectionService() { return results.toTypedArray() } - private fun getAnonymizedAlias(number: String): String { - val prefs = getSharedPreferences("anonymized_numbers", MODE_PRIVATE) - - // Return existing alias if already mapped - val existing = prefs.getString(number, null) - if (existing != null) return existing - - // Start from current counter - var counter = prefs.getInt("counter", 1) - var alias: String - - // Find the first unused alias (safety check) - while (true) { - alias = "#$counter" - if (!prefs.all.containsValue(alias)) break - counter++ - } - - // Store new alias and increment counter - prefs.edit() - .putString(number, alias) - .putInt("counter", counter + 1) - .apply() - - return alias - } - private fun isInternationalNumber(phoneNumber: String): Boolean { val telephony = getSystemService(TelephonyManager::class.java) ?: return true val simCountryIso = telephony.simCountryIso?.lowercase() ?: return true diff --git a/app/src/main/java/partisan/weforge/xyz/pulse/MainFragment.kt b/app/src/main/java/partisan/weforge/xyz/pulse/MainFragment.kt index ae75e24..72cc529 100644 --- a/app/src/main/java/partisan/weforge/xyz/pulse/MainFragment.kt +++ b/app/src/main/java/partisan/weforge/xyz/pulse/MainFragment.kt @@ -51,8 +51,8 @@ class MainFragment : Fragment() { emitter = Emitter(duration = 100, TimeUnit.MILLISECONDS) .perSecond(100), - speed = 25f, - maxSpeed = 30f, + speed = 30f, + maxSpeed = 40f, damping = 0.85f, spread = 360, position = Position.Relative(0.5, 0.5) diff --git a/app/src/main/java/partisan/weforge/xyz/pulse/Preferences.kt b/app/src/main/java/partisan/weforge/xyz/pulse/Preferences.kt index 2552cf6..753fdb5 100644 --- a/app/src/main/java/partisan/weforge/xyz/pulse/Preferences.kt +++ b/app/src/main/java/partisan/weforge/xyz/pulse/Preferences.kt @@ -38,8 +38,8 @@ class Preferences(private val context: Context) { val isEnabled: Boolean get() = isServiceEnabledByUser && hasGeneralPermissions(context) && - hasCallRedirectionRole(context) && - (popupEnabled.not() || hasDrawOverlays(context)) + hasDrawOverlays(context) && + hasCallRedirectionRole(context) enum class PopupEffect { NONE, FADE, SCALE, BOUNCE, FLOP, MATRIX, SLIDE_SNAP, GAMER_MODE, RANDOM