Skip to content
Closed
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
55 changes: 54 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="internalOnly">

<!-- EXISTING PERMISSIONS -->
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="PackageVisibilityPolicy,QueryAllPackagesPermission" />
Expand All @@ -26,9 +27,12 @@
tools:ignore="ForegroundServicesPolicy" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />

<uses-permission android:name="android.permission.SET_ACTIVITY_WATCHER" />

<!-- NEW PERMISSIONS FOR SYSTEM SETTINGS RESTRICTION -->
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
<uses-permission android:name="android.permission.ACCESS_DEVICE_ADMIN" />

<application
android:name=".AppLockApplication"
android:allowBackup="true"
Expand All @@ -43,6 +47,7 @@
android:theme="@style/Theme.AppLock"
tools:targetApi="33">

<!-- MAIN ACTIVITY -->
<activity
android:name=".MainActivity"
android:exported="true"
Expand All @@ -53,6 +58,7 @@
</intent-filter>
</activity>

<!-- LOCK SCREEN ACTIVITY -->
<activity
android:name=".features.lockscreen.ui.PasswordOverlayActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
Expand All @@ -61,17 +67,20 @@
android:taskAffinity=""
android:theme="@android:style/Theme.Material.NoActionBar.TranslucentDecor" />

<!-- ADMIN DISABLE ACTIVITY -->
<activity
android:name=".features.admin.AdminDisableActivity"
android:exported="false"
android:theme="@style/Theme.AppLock" />

<!-- SHIZUKU SERVICE -->
<service
android:name=".services.ShizukuAppLockService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="specialUse|systemExempted" />

<!-- EXPERIMENTAL SERVICE -->
<service
android:name=".services.ExperimentalAppLockService"
android:enabled="true"
Expand All @@ -82,6 +91,7 @@
android:value="app_lock" />
</service>

<!-- ACCESSIBILITY SERVICE - UPDATED EVENT TYPES -->
<service
android:name=".services.AppLockAccessibilityService"
android:exported="false"
Expand All @@ -100,6 +110,7 @@
android:value="accessibility" />
</service>

<!-- DEVICE ADMIN RECEIVER -->
<receiver
android:name=".core.broadcast.DeviceAdmin"
android:description="@string/device_admin_description"
Expand All @@ -113,6 +124,7 @@
android:resource="@xml/device_admin_policies" />
</receiver>

<!-- BOOT RECEIVER -->
<receiver
android:name=".core.broadcast.BootReceiver"
android:enabled="true"
Expand All @@ -126,6 +138,45 @@
</intent-filter>
</receiver>

<!-- NEW: BROADCAST RECEIVER FOR SYSTEM SETTINGS INTENT INTERCEPTION -->
<receiver
android:name=".core.broadcast.SettingsIntentInterceptor"
android:exported="false"
android:enabled="true"
android:permission="android.permission.MANAGE_APP_PERMISSIONS">

<intent-filter android:priority="1000">
<!-- Overlay/Draw Over Apps Settings -->
<action android:name="android.intent.action.MANAGE_OVERLAY_PERMISSION" />
<action android:name="android.settings.MANAGE_OVERLAY_PERMISSION" />

<!-- Usage Access Settings -->
<action android:name="android.settings.USAGE_ACCESS_SETTINGS" />
<action android:name="android.intent.action.USAGE_ACCESS_SETTINGS" />

<!-- Accessibility Settings -->
<action android:name="android.settings.ACCESSIBILITY_SETTINGS" />
<action android:name="android.intent.action.ACCESSIBILITY_SETTINGS" />

<!-- Device Administrator Settings -->
<action android:name="android.settings.SECURITY_SETTINGS" />
<action android:name="android.intent.action.SECURITY_SETTINGS" />
<action android:name="com.android.settings.DEVICE_ADMIN_DELETE_CONFIRM" />
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
<action android:name="android.app.action.DEVICE_ADMIN_DISABLED" />

<!-- Battery Optimization Settings -->
<action android:name="android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS" />
<action android:name="android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<action android:name="android.intent.action.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

<!-- Samsung-specific Settings -->
<action android:name="com.android.settings.MANAGE_APP_PERMISSIONS" />
<action android:name="com.sec.android.settings.MANAGE_PERMISSION" />
</intent-filter>
</receiver>

<!-- FILE PROVIDER -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
Expand All @@ -136,6 +187,7 @@
android:resource="@xml/file_paths" />
</provider>

<!-- SHIZUKU PROVIDER -->
<provider
android:name="rikka.shizuku.ShizukuProvider"
android:authorities="${applicationId}.shizuku"
Expand All @@ -145,4 +197,5 @@
android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" />

</application>

</manifest>
22 changes: 22 additions & 0 deletions app/src/main/java/dev/pranav/applock/BatteryProtection.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package dev.pranav.applock.core.security

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.PowerManager
import android.provider.Settings

fun enforceBatteryExemption(context: Context) {

val pm = context.getSystemService(PowerManager::class.java)

if (pm.isIgnoringBatteryOptimizations(context.packageName)) return

val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)

intent.data = Uri.parse("package:${context.packageName}")

intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK

context.startActivity(intent)
}
27 changes: 27 additions & 0 deletions app/src/main/java/dev/pranav/applock/RestrictSettingsState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package dev.pranav.applock.core.security

data class RestrictSettingsState(

val blockOverlaySettings: Boolean = false,

val blockUsageAccessSettings: Boolean = false,

val blockAccessibilitySettings: Boolean = false,

val blockDeviceAdminSettings: Boolean = false,

val requireBatteryExemption: Boolean = false
)

enum class RestrictSetting {

OVERLAY,

USAGE,

ACCESSIBILITY,

DEVICE_ADMIN,

BATTERY
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package dev.pranav.applock.core.broadcast

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import dev.pranav.applock.core.utils.LogUtils
import dev.pranav.applock.core.utils.appLockRepository
import dev.pranav.applock.core.utils.systemSettingsRestrictionManager

/**
* COMPLETE FILE - Copy to app/src/main/java/dev/pranav/applock/core/broadcast/
*
* Broadcast receiver that intercepts attempts to open restricted system settings pages.
* Register in AndroidManifest.xml with the provided intent filters.
*/
class SettingsIntentInterceptor : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent?) {
if (intent == null) {
return
}

try {
val repository = context.appLockRepository()

if (!repository.isAntiUninstallEnabled()) {
return
}

val restrictionManager = context.systemSettingsRestrictionManager()

if (restrictionManager.isIntentRestricted(intent)) {
blockAndShowLockScreen(context, intent)
abortBroadcast()
}
} catch (e: Exception) {
LogUtils.logError("Error in SettingsIntentInterceptor", e)
}
}

/**
* Block the settings intent and show lock screen instead.
*/
private fun blockAndShowLockScreen(context: Context, intent: Intent) {
try {
val action = intent.action ?: "Unknown"
LogUtils.logSecurityEvent("Blocked attempt to access settings: $action")

val lockScreenIntent = Intent(context, PasswordOverlayActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_CLEAR_TOP or
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
putExtra("isRestrictedSettings", true)
putExtra("restrictedAction", intent.action)
}
context.startActivity(lockScreenIntent)

val homeIntent = Intent(Intent.ACTION_MAIN).apply {
addCategory(Intent.CATEGORY_HOME)
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
context.startActivity(homeIntent)
} catch (e: Exception) {
LogUtils.logError("Failed to block and show lock screen", e)
}
}

companion object {
private const val TAG = "SettingsIntentInterceptor"
}
}

/**
* Alternative implementation: Activity that intercepts settings intents.
* Can be used as a bridge activity to intercept intents before they reach system settings.
* Optional - only use if BroadcastReceiver approach doesn't work on your device.
*/
class SettingsIntentInterceptorActivity : android.app.Activity() {

override fun onCreate(savedInstanceState: android.os.Bundle?) {
super.onCreate(savedInstanceState)

try {
val intent = intent
val repository = applicationContext.appLockRepository()

if (repository.isAntiUninstallEnabled()) {
val restrictionManager = applicationContext.systemSettingsRestrictionManager()

if (restrictionManager.isIntentRestricted(intent)) {
LogUtils.logSecurityEvent("Blocked attempt to access settings: ${intent.action}")

val lockScreenIntent = Intent(applicationContext, PasswordOverlayActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_CLEAR_TOP or
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
putExtra("isRestrictedSettings", true)
}
startActivity(lockScreenIntent)

finish()
return
}
}

startActivity(intent)
finish()
} catch (e: Exception) {
LogUtils.logError("Error in SettingsIntentInterceptorActivity", e)
finish()
}
}
}
Loading
Loading