diff --git a/app/build.gradle b/app/build.gradle
index 0bb1039..223661b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -69,4 +69,5 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.cardview:cardview:1.0.0'
+ implementation 'nl.dionsegijn:konfetti-xml:2.0.2' // This library holds the fabric of reality together please dont remove it at any costs >:3
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a54dd88..6004724 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -16,13 +16,14 @@
android:theme="@style/Theme.Pulse">
+
requestGeneralPermissions()
+ !hasGeneralPermissions(this) -> registerForGeneralPermissions.launch(REQUIRED_PERMISSIONS)
!hasDrawOverlays() -> requestDrawOverlays()
!hasCallRedirectionRole() -> requestCallRedirectionRole()
}
}
private fun hasPermissions(): Boolean {
- return hasGeneralPermissions() && hasDrawOverlays() && hasCallRedirectionRole()
+ return hasGeneralPermissions(this) &&
+ hasDrawOverlays(this) &&
+ hasCallRedirectionRole(this)
}
private fun requestDrawOverlays() {
registerForDrawOverlays.launch(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION))
}
- private fun requestGeneralPermissions() {
- registerForGeneralPermissions.launch(PERMISSIONS)
- }
-
- private fun hasGeneralPermissions(): Boolean {
- return !PERMISSIONS.any { checkSelfPermission(it) != PackageManager.PERMISSION_GRANTED }
- }
-
private fun hasDrawOverlays(): Boolean {
return Settings.canDrawOverlays(this)
}
diff --git a/app/src/main/java/partisan/weforge/xyz/pulse/Permissions.kt b/app/src/main/java/partisan/weforge/xyz/pulse/Permissions.kt
new file mode 100644
index 0000000..f33ec8d
--- /dev/null
+++ b/app/src/main/java/partisan/weforge/xyz/pulse/Permissions.kt
@@ -0,0 +1,28 @@
+
+package partisan.weforge.xyz.pulse
+
+import android.Manifest
+import android.content.Context
+import android.content.pm.PackageManager
+import android.provider.Settings
+import android.app.role.RoleManager
+
+val REQUIRED_PERMISSIONS = arrayOf(
+ Manifest.permission.READ_CONTACTS,
+ Manifest.permission.CALL_PHONE,
+)
+
+fun hasGeneralPermissions(context: Context): Boolean {
+ return REQUIRED_PERMISSIONS.all {
+ context.checkSelfPermission(it) == PackageManager.PERMISSION_GRANTED
+ }
+}
+
+fun hasDrawOverlays(context: Context): Boolean {
+ return Settings.canDrawOverlays(context)
+}
+
+fun hasCallRedirectionRole(context: Context): Boolean {
+ val roleManager = context.getSystemService(RoleManager::class.java)
+ return roleManager?.isRoleHeld(RoleManager.ROLE_CALL_REDIRECTION) ?: false
+}
diff --git a/app/src/main/java/partisan/weforge/xyz/pulse/WelcomeActivity.kt b/app/src/main/java/partisan/weforge/xyz/pulse/WelcomeActivity.kt
new file mode 100644
index 0000000..c0577dc
--- /dev/null
+++ b/app/src/main/java/partisan/weforge/xyz/pulse/WelcomeActivity.kt
@@ -0,0 +1,107 @@
+package partisan.weforge.xyz.pulse
+
+import android.Manifest
+import android.app.role.RoleManager
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Bundle
+import android.provider.Settings
+import android.view.View
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.appcompat.app.AppCompatActivity
+import nl.dionsegijn.konfetti.core.Party
+import nl.dionsegijn.konfetti.core.Position
+import nl.dionsegijn.konfetti.core.emitter.Emitter
+import nl.dionsegijn.konfetti.xml.KonfettiView
+import partisan.weforge.xyz.pulse.databinding.ActivityWelcomeBinding
+import java.util.concurrent.TimeUnit
+import partisan.weforge.xyz.pulse.hasGeneralPermissions
+import partisan.weforge.xyz.pulse.hasDrawOverlays
+import partisan.weforge.xyz.pulse.hasCallRedirectionRole
+import partisan.weforge.xyz.pulse.REQUIRED_PERMISSIONS
+
+class WelcomeActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityWelcomeBinding
+ private lateinit var prefs: Preferences
+ private var roleManager: RoleManager? = null
+
+ private val requestPermissionsLauncher = registerForActivityResult(
+ ActivityResultContracts.RequestMultiplePermissions()
+ ) {}
+
+ private val requestOverlayLauncher = registerForActivityResult(
+ ActivityResultContracts.StartActivityForResult()
+ ) {}
+
+ private val requestRoleLauncher = registerForActivityResult(
+ ActivityResultContracts.StartActivityForResult()
+ ) {}
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (hasGeneralPermissions(this) && hasDrawOverlays(this) && hasCallRedirectionRole(this)) {
+ startActivity(Intent(this, MainActivity::class.java))
+ finish()
+ return
+ }
+
+ binding = ActivityWelcomeBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ prefs = Preferences(this)
+ roleManager = getSystemService(RoleManager::class.java)
+
+ binding.activateButton.setOnClickListener {
+ when {
+ !hasGeneralPermissions(this) -> {
+ requestPermissionsLauncher.launch(REQUIRED_PERMISSIONS)
+ }
+ !hasDrawOverlays(this) -> {
+ requestOverlayLauncher.launch(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION))
+ }
+ !hasCallRedirectionRole(this) -> {
+ requestRoleLauncher.launch(roleManager?.createRequestRoleIntent(RoleManager.ROLE_CALL_REDIRECTION))
+ }
+ else -> {
+ prefs.isEnabled = true
+ showConfettiAndContinue()
+ }
+ }
+ }
+ }
+
+ private fun showConfettiAndContinue() {
+ binding.appIcon.post {
+ val iconLocation = IntArray(2)
+ binding.appIcon.getLocationOnScreen(iconLocation)
+
+ val iconCenterX = iconLocation[0] + binding.appIcon.width / 2f
+ val iconCenterY = iconLocation[1] + binding.appIcon.height / 2f
+
+ val rootWidth = binding.root.width.toFloat()
+ val rootHeight = binding.root.height.toFloat()
+
+ val relativeX = (iconCenterX / rootWidth).toDouble()
+ val relativeY = (iconCenterY / rootHeight).toDouble()
+
+ binding.konfettiView.visibility = View.VISIBLE
+ binding.konfettiView.start(
+ Party(
+ speed = 30f,
+ maxSpeed = 50f,
+ damping = 0.9f,
+ spread = 360,
+ colors = listOf(0xfce18a, 0xff726d, 0xf4306d, 0xb48def),
+ position = Position.Relative(relativeX, relativeY),
+ emitter = Emitter(duration = 2, TimeUnit.SECONDS).perSecond(100)
+ )
+ )
+
+ binding.konfettiView.postDelayed({
+ startActivity(Intent(this, MainActivity::class.java))
+ finish()
+ }, 2000)
+ }
+ }
+}
diff --git a/app/src/main/res/layout/activity_welcome.xml b/app/src/main/res/layout/activity_welcome.xml
new file mode 100644
index 0000000..77183e8
--- /dev/null
+++ b/app/src/main/res/layout/activity_welcome.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index fe77fda..2234d6b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,7 +1,7 @@
Pulse
- The app will try to redirect outgoing calls to Signal/Telegram/Threema/WhatsApp if available. For work it requires many permissions. Click on the toggle and grant permissions until it turns ON.
+ App will try to redirect outgoing calls to E2EE apps if available.
Redirecting to %1$s
Signal
Telegram
@@ -10,4 +10,6 @@
The delay before a call will be redirected.
Popup position
Fallback
+ To start, grant the required permissions and tap the Activate button.
+ Activate
\ No newline at end of file