Self-hosted, federated location sharing app and server that prioritizes user privacy and security
end-to-end-encryption location-sharing privacy self-hosted federated
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add Android permissions and runtime permission prompts

azomDev 90c04623 53dba4de

+81 -20
+11 -20
app/src-tauri/gen/android/app/src/main/AndroidManifest.xml
··· 1 - <?xml version="1.0" encoding="utf-8"?> 1 + <?xml version="1.0" encoding="utf-8" ?> 2 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"> 3 3 <uses-permission android:name="android.permission.INTERNET" /> 4 + <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 5 + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 6 + <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> 7 + <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> 8 + <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" /> 9 + <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> 4 10 5 11 <!-- AndroidTV support --> 6 12 <uses-feature android:name="android.software.leanback" android:required="false" /> 7 13 8 - <application 9 - android:icon="@mipmap/ic_launcher" 10 - android:label="@string/app_name" 11 - android:theme="@style/Theme.privacypin" 12 - android:usesCleartextTraffic="${usesCleartextTraffic}"> 13 - <activity 14 - android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode" 15 - android:launchMode="singleTask" 16 - android:label="@string/main_activity_title" 17 - android:name=".MainActivity" 18 - android:exported="true"> 14 + <application android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/Theme.privacypin" android:usesCleartextTraffic="${usesCleartextTraffic}"> 15 + <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode" android:launchMode="singleTask" android:label="@string/main_activity_title" android:name=".MainActivity" android:exported="true"> 19 16 <intent-filter> 20 17 <action android:name="android.intent.action.MAIN" /> 21 18 <category android:name="android.intent.category.LAUNCHER" /> ··· 24 21 </intent-filter> 25 22 </activity> 26 23 27 - <provider 28 - android:name="androidx.core.content.FileProvider" 29 - android:authorities="${applicationId}.fileprovider" 30 - android:exported="false" 31 - android:grantUriPermissions="true"> 32 - <meta-data 33 - android:name="android.support.FILE_PROVIDER_PATHS" 34 - android:resource="@xml/file_paths" /> 24 + <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> 25 + <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> 35 26 </provider> 36 27 </application> 37 28 </manifest>
+70
app/src-tauri/gen/android/app/src/main/java/dev/azom/privacypin/MainActivity.kt
··· 1 1 package dev.azom.privacypin 2 2 3 + import android.Manifest 4 + import android.content.pm.PackageManager 5 + import android.os.Build 3 6 import android.os.Bundle 4 7 import androidx.activity.enableEdgeToEdge 8 + import androidx.activity.result.ActivityResultLauncher 9 + import androidx.activity.result.contract.ActivityResultContracts 10 + import androidx.core.content.ContextCompat 5 11 6 12 class MainActivity : TauriActivity() { 13 + private lateinit var requestForegroundLocationLauncher: ActivityResultLauncher<Array<String>> 14 + private lateinit var requestBackgroundLocationLauncher: ActivityResultLauncher<String> 15 + private lateinit var requestNotificationsLauncher: ActivityResultLauncher<String> 16 + 7 17 override fun onCreate(savedInstanceState: Bundle?) { 8 18 enableEdgeToEdge() 9 19 super.onCreate(savedInstanceState) 20 + registerPermissionLaunchers() 21 + requestRequiredPermissions() 22 + } 23 + 24 + private fun registerPermissionLaunchers() { 25 + requestForegroundLocationLauncher = 26 + registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { 27 + requestRequiredPermissions() 28 + } 29 + 30 + requestBackgroundLocationLauncher = 31 + registerForActivityResult(ActivityResultContracts.RequestPermission()) { 32 + requestRequiredPermissions() 33 + } 34 + 35 + requestNotificationsLauncher = 36 + registerForActivityResult(ActivityResultContracts.RequestPermission()) { 37 + requestRequiredPermissions() 38 + } 39 + } 40 + 41 + private fun requestRequiredPermissions() { 42 + if (!hasForegroundLocation()) { 43 + requestForegroundLocationLauncher.launch( 44 + arrayOf( 45 + Manifest.permission.ACCESS_COARSE_LOCATION, 46 + Manifest.permission.ACCESS_FINE_LOCATION, 47 + ) 48 + ) 49 + return 50 + } 51 + 52 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && !hasBackgroundLocation()) { 53 + requestBackgroundLocationLauncher.launch(Manifest.permission.ACCESS_BACKGROUND_LOCATION) 54 + return 55 + } 56 + 57 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && !hasNotifications()) { 58 + requestNotificationsLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) 59 + } 60 + } 61 + 62 + private fun hasForegroundLocation(): Boolean { 63 + val coarse = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) 64 + val fine = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) 65 + return coarse == PackageManager.PERMISSION_GRANTED || fine == PackageManager.PERMISSION_GRANTED 66 + } 67 + 68 + private fun hasBackgroundLocation(): Boolean { 69 + return ContextCompat.checkSelfPermission( 70 + this, 71 + Manifest.permission.ACCESS_BACKGROUND_LOCATION 72 + ) == PackageManager.PERMISSION_GRANTED 73 + } 74 + 75 + private fun hasNotifications(): Boolean { 76 + return ContextCompat.checkSelfPermission( 77 + this, 78 + Manifest.permission.POST_NOTIFICATIONS 79 + ) == PackageManager.PERMISSION_GRANTED 10 80 } 11 81 }