Add shortcuts to lock screen, disable camera or mute

This commit is contained in:
BinTianqi
2025-04-20 10:54:08 +08:00
parent a30a9abb3c
commit 19acf94e7b
8 changed files with 109 additions and 24 deletions

View File

@@ -44,6 +44,7 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.content.edit import androidx.core.content.edit
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bintianqi.owndroid.ui.FunctionItem import com.bintianqi.owndroid.ui.FunctionItem
@@ -85,13 +86,22 @@ fun SettingsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
@Composable @Composable
fun SettingsOptionsScreen(onNavigateUp: () -> Unit) { fun SettingsOptionsScreen(onNavigateUp: () -> Unit) {
val sp = SharedPrefs(LocalContext.current) val context = LocalContext.current
val sp = SharedPrefs(context)
MyScaffold(R.string.options, onNavigateUp, 0.dp) { MyScaffold(R.string.options, onNavigateUp, 0.dp) {
SwitchItem( SwitchItem(
R.string.show_dangerous_features, icon = R.drawable.warning_fill0, R.string.show_dangerous_features, icon = R.drawable.warning_fill0,
getState = { sp.displayDangerousFeatures }, getState = { sp.displayDangerousFeatures },
onCheckedChange = { sp.displayDangerousFeatures = it } onCheckedChange = { sp.displayDangerousFeatures = it }
) )
SwitchItem(
R.string.shortcuts, icon = R.drawable.open_in_new,
getState = { sp.shortcuts }, onCheckedChange = {
sp.shortcuts = it
ShortcutManagerCompat.removeAllDynamicShortcuts(context)
createShortcuts(context)
}
)
} }
} }

View File

@@ -22,6 +22,7 @@ class SharedPrefs(context: Context) {
var lockPasswordHash by StringSharedPref("lock.password.sha256") var lockPasswordHash by StringSharedPref("lock.password.sha256")
var biometricsUnlock by BooleanSharedPref("lock.biometrics") var biometricsUnlock by BooleanSharedPref("lock.biometrics")
var applicationsListView by BooleanSharedPref("applications.list_view", true) var applicationsListView by BooleanSharedPref("applications.list_view", true)
var shortcuts by BooleanSharedPref("shortcuts", true)
} }
private class BooleanSharedPref(val key: String, val defValue: Boolean = false): ReadWriteProperty<SharedPrefs, Boolean> { private class BooleanSharedPref(val key: String, val defValue: Boolean = false): ReadWriteProperty<SharedPrefs, Boolean> {

View File

@@ -1,17 +1,72 @@
package com.bintianqi.owndroid package com.bintianqi.owndroid
import android.app.Activity import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import com.bintianqi.owndroid.dpm.getDPM import com.bintianqi.owndroid.dpm.getDPM
import com.bintianqi.owndroid.dpm.getReceiver
class ShortcutsReceiverActivity: Activity() { class ShortcutsReceiverActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
try { try {
if(intent.action == "com.bintianqi.owndroid.action.LOCK") { val action = intent.action?.removePrefix("com.bintianqi.owndroid.action.")
getDPM().lockNow() if (action != null && SharedPrefs(this).shortcuts) {
val dpm = getDPM()
val receiver = getReceiver()
when (action) {
"LOCK" -> dpm.lockNow()
"DISABLE_CAMERA" -> {
dpm.setCameraDisabled(receiver, !dpm.getCameraDisabled(receiver))
createShortcuts(this)
}
"MUTE" -> {
dpm.setMasterVolumeMuted(receiver, !dpm.isMasterVolumeMuted(receiver))
createShortcuts(this)
}
}
} }
} catch(_: Exception) {} } finally {
finish() finish()
}
} }
} }
fun createShortcuts(context: Context) {
if (!SharedPrefs(context).shortcuts) return
val action = "com.bintianqi.owndroid.action"
val baseIntent = Intent(context, ShortcutsReceiverActivity::class.java)
val dpm = context.getDPM()
val receiver = context.getReceiver()
val cameraDisabled = dpm.getCameraDisabled(receiver)
val muted = dpm.isMasterVolumeMuted(receiver)
val list = listOf(
ShortcutInfoCompat.Builder(context, "LOCK")
.setIcon(IconCompat.createWithResource(context, R.drawable.screen_lock_portrait_fill0))
.setShortLabel(context.getString(R.string.lock_screen))
.setIntent(Intent(baseIntent).setAction("$action.LOCK")),
ShortcutInfoCompat.Builder(context, "DISABLE_CAMERA")
.setIcon(
IconCompat.createWithResource(
context,
if (cameraDisabled) R.drawable.photo_camera_fill0 else R.drawable.no_photography_fill0
)
)
.setShortLabel(context.getString(if (cameraDisabled) R.string.enable_camera else R.string.disable_cam))
.setIntent(Intent(baseIntent).setAction("$action.DISABLE_CAMERA")),
ShortcutInfoCompat.Builder(context, "MUTE")
.setIcon(
IconCompat.createWithResource(
context,
if (muted) R.drawable.volume_up_fill0 else R.drawable.volume_off_fill0
)
)
.setShortLabel(context.getString(if (muted) R.string.unmute else R.string.mute))
.setIntent(Intent(baseIntent).setAction("$action.MUTE"))
)
ShortcutManagerCompat.setDynamicShortcuts(context, list.map { it.build() })
}

View File

@@ -22,12 +22,14 @@ import android.util.Log
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.Receiver import com.bintianqi.owndroid.Receiver
import com.bintianqi.owndroid.SharedPrefs import com.bintianqi.owndroid.SharedPrefs
import com.bintianqi.owndroid.ShortcutsReceiverActivity import com.bintianqi.owndroid.ShortcutsReceiverActivity
import com.bintianqi.owndroid.backToHomeStateFlow import com.bintianqi.owndroid.backToHomeStateFlow
import com.bintianqi.owndroid.createShortcuts
import com.bintianqi.owndroid.myPrivilege import com.bintianqi.owndroid.myPrivilege
import com.rosan.dhizuku.api.Dhizuku import com.rosan.dhizuku.api.Dhizuku
import com.rosan.dhizuku.api.Dhizuku.binderWrapper import com.rosan.dhizuku.api.Dhizuku.binderWrapper
@@ -520,26 +522,17 @@ fun parsePackageInstallerMessage(context: Context, result: Intent): String {
fun handlePrivilegeChange(context: Context) { fun handlePrivilegeChange(context: Context) {
val privilege = myPrivilege.value val privilege = myPrivilege.value
val activated = privilege.device || privilege.profile val activated = privilege.device || privilege.profile
val sp = SharedPrefs(context)
if(activated) { if(activated) {
createShortcuts(context)
if(!privilege.dhizuku) { if(!privilege.dhizuku) {
setDefaultAffiliationID(context) setDefaultAffiliationID(context)
if(VERSION.SDK_INT >= 25) {
val sm = context.getSystemService(ShortcutManager::class.java)
val lockIntent = Intent("com.bintianqi.owndroid.action.LOCK")
.setComponent(ComponentName(context, ShortcutsReceiverActivity::class.java))
val shortcut = ShortcutInfo.Builder(context, "LockScreen")
.setShortLabel(context.getString(R.string.lock_now))
.setIcon(Icon.createWithBitmap(context.getDrawable(R.drawable.screen_lock_portrait_fill0)?.toBitmap()))
.setIntent(lockIntent)
sm.addDynamicShortcuts(listOf(shortcut.build()))
}
} }
} else { } else {
SharedPrefs(context).isDefaultAffiliationIdSet = false sp.isDefaultAffiliationIdSet = false
if(VERSION.SDK_INT >= 25) { if(VERSION.SDK_INT >= 25) {
val sm = context.getSystemService(ShortcutManager::class.java) ShortcutManagerCompat.removeAllDynamicShortcuts(context)
sm.removeDynamicShortcuts(listOf("LockScreen"))
} }
SharedPrefs(context).isApiEnabled = false sp.isApiEnabled = false
} }
} }

View File

@@ -122,6 +122,7 @@ import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.NotificationUtils import com.bintianqi.owndroid.NotificationUtils
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.SharedPrefs import com.bintianqi.owndroid.SharedPrefs
import com.bintianqi.owndroid.createShortcuts
import com.bintianqi.owndroid.formatFileSize import com.bintianqi.owndroid.formatFileSize
import com.bintianqi.owndroid.humanReadableDate import com.bintianqi.owndroid.humanReadableDate
import com.bintianqi.owndroid.myPrivilege import com.bintianqi.owndroid.myPrivilege
@@ -250,8 +251,11 @@ fun SystemOptionsScreen(onNavigateUp: () -> Unit) {
val privilege by myPrivilege.collectAsStateWithLifecycle() val privilege by myPrivilege.collectAsStateWithLifecycle()
var dialog by remember { mutableIntStateOf(0) } var dialog by remember { mutableIntStateOf(0) }
MyScaffold(R.string.options, onNavigateUp, 0.dp) { MyScaffold(R.string.options, onNavigateUp, 0.dp) {
SwitchItem(R.string.disable_cam, icon = R.drawable.photo_camera_fill0, SwitchItem(R.string.disable_cam, icon = R.drawable.no_photography_fill0,
getState = { dpm.getCameraDisabled(null) }, onCheckedChange = { dpm.setCameraDisabled(receiver,it) } getState = { dpm.getCameraDisabled(null) }, onCheckedChange = {
dpm.setCameraDisabled(receiver, it)
createShortcuts(context)
}
) )
SwitchItem(R.string.disable_screen_capture, icon = R.drawable.screenshot_fill0, SwitchItem(R.string.disable_screen_capture, icon = R.drawable.screenshot_fill0,
getState = { dpm.getScreenCaptureDisabled(null) }, onCheckedChange = { dpm.setScreenCaptureDisabled(receiver,it) } getState = { dpm.getScreenCaptureDisabled(null) }, onCheckedChange = { dpm.setScreenCaptureDisabled(receiver,it) }
@@ -275,7 +279,10 @@ fun SystemOptionsScreen(onNavigateUp: () -> Unit) {
} }
} }
SwitchItem(R.string.master_mute, icon = R.drawable.volume_off_fill0, SwitchItem(R.string.master_mute, icon = R.drawable.volume_off_fill0,
getState = { dpm.isMasterVolumeMuted(receiver) }, onCheckedChange = { dpm.setMasterVolumeMuted(receiver,it) } getState = { dpm.isMasterVolumeMuted(receiver) }, onCheckedChange = {
dpm.setMasterVolumeMuted(receiver,it)
createShortcuts(context)
}
) )
if(VERSION.SDK_INT >= 26) { if(VERSION.SDK_INT >= 26) {
SwitchItem(R.string.backup_service, icon = R.drawable.backup_fill0, SwitchItem(R.string.backup_service, icon = R.drawable.backup_fill0,

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="m880,765 l-80,-80v-405L638,280l-73,-80L395,200l-38,42 -57,-57 60,-65h240l74,80h126q33,0 56.5,23.5T880,280v485ZM160,840q-33,0 -56.5,-23.5T80,760v-480q0,-33 23.5,-56.5T160,200h41l80,80L160,280v480h601l80,80L160,840ZM626,625q-25,34 -62.5,54.5T480,700q-75,0 -127.5,-52.5T300,520q0,-46 20.5,-83.5T375,374l58,58q-24,13 -38.5,36T380,520q0,42 29,71t71,29q29,0 52,-14.5t36,-38.5l58,58ZM608,392q25,24 38.5,57t13.5,71v12q0,6 -1,12L456,341q6,-1 12,-1h12q38,0 71,13.5t57,38.5ZM819,932 L27,140l57,-57L876,875l-57,57ZM407,520ZM578,463Z"
android:fillColor="#000000"/>
</vector>

View File

@@ -117,18 +117,22 @@
<!--System--> <!--System-->
<string name="system">系统</string> <string name="system">系统</string>
<string name="disable_cam">禁用相机</string> <string name="disable_cam">禁用相机</string>
<string name="enable_camera">启用相机</string>
<string name="disable_screen_capture">禁止屏幕捕获</string> <string name="disable_screen_capture">禁止屏幕捕获</string>
<string name="disable_status_bar">禁用状态栏</string> <string name="disable_status_bar">禁用状态栏</string>
<string name="auto_time">自动设置时间</string> <string name="auto_time">自动设置时间</string>
<string name="auto_timezone">自动设置时区</string> <string name="auto_timezone">自动设置时区</string>
<string name="require_auto_time">要求自动时间</string> <string name="require_auto_time">要求自动时间</string>
<string name="master_mute">全局静音</string> <string name="master_mute">全局静音</string>
<string name="mute">静音</string>
<string name="unmute">取消静音</string>
<string name="backup_service">备份服务</string> <string name="backup_service">备份服务</string>
<string name="disable_bt_contact_share">禁止蓝牙分享联系人</string> <string name="disable_bt_contact_share">禁止蓝牙分享联系人</string>
<string name="common_criteria_mode">通用标准模式</string> <string name="common_criteria_mode">通用标准模式</string>
<string name="disable_usb_signal">禁用USB信号</string> <string name="disable_usb_signal">禁用USB信号</string>
<string name="keyguard">锁屏</string> <string name="keyguard">锁屏</string>
<string name="lock_now">立即锁屏</string> <string name="lock_now">立即锁屏</string>
<string name="lock_screen">锁屏</string>
<string name="evict_credential_encryption_key">移除凭证加密密钥</string> <string name="evict_credential_encryption_key">移除凭证加密密钥</string>
<string name="hardware_monitor">硬件监视器</string> <string name="hardware_monitor">硬件监视器</string>
<string name="refresh_interval">刷新间隔</string> <string name="refresh_interval">刷新间隔</string>
@@ -551,6 +555,7 @@
<string name="project_homepage">项目主页</string> <string name="project_homepage">项目主页</string>
<string name="appearance">外观</string> <string name="appearance">外观</string>
<string name="shortcuts">快捷方式</string>
<string name="app_lock">应用锁</string> <string name="app_lock">应用锁</string>
<string name="minimum_length_4">长度不得小于4</string> <string name="minimum_length_4">长度不得小于4</string>
<string name="leave_empty_to_remain_unchanged">留空以保持未更改</string> <string name="leave_empty_to_remain_unchanged">留空以保持未更改</string>

View File

@@ -126,18 +126,22 @@
<!--System--> <!--System-->
<string name="system">System</string> <string name="system">System</string>
<string name="disable_cam">Disable camera</string> <string name="disable_cam">Disable camera</string>
<string name="enable_camera">Enable camera</string>
<string name="disable_screen_capture">Disable screen capture</string> <string name="disable_screen_capture">Disable screen capture</string>
<string name="disable_status_bar">Disable status bar</string> <string name="disable_status_bar">Disable status bar</string>
<string name="auto_time">Auto time</string> <string name="auto_time">Auto time</string>
<string name="require_auto_time">Require auto time</string> <string name="require_auto_time">Require auto time</string>
<string name="auto_timezone">Auto timezone</string> <string name="auto_timezone">Auto timezone</string>
<string name="master_mute">Master volume mute</string> <string name="master_mute">Master volume mute</string>
<string name="mute">Mute</string>
<string name="unmute">Unmute</string>
<string name="backup_service">Backup service</string> <string name="backup_service">Backup service</string>
<string name="disable_bt_contact_share">Disable bluetooth contact sharing</string> <string name="disable_bt_contact_share">Disable bluetooth contact sharing</string>
<string name="common_criteria_mode">Common criteria mode</string> <string name="common_criteria_mode">Common criteria mode</string>
<string name="disable_usb_signal">Disable USB signal</string> <string name="disable_usb_signal">Disable USB signal</string>
<string name="keyguard">Keyguard</string> <string name="keyguard">Keyguard</string>
<string name="lock_now">Lock screen now</string> <string name="lock_now">Lock screen now</string>
<string name="lock_screen">Lock screen</string>
<string name="evict_credential_encryption_key">Evict credential encryption key</string> <string name="evict_credential_encryption_key">Evict credential encryption key</string>
<string name="hardware_monitor">Hardware monitor</string> <string name="hardware_monitor">Hardware monitor</string>
<string name="refresh_interval">Refresh interval</string> <string name="refresh_interval">Refresh interval</string>
@@ -584,6 +588,7 @@
<string name="project_homepage">Project homepage</string> <string name="project_homepage">Project homepage</string>
<string name="appearance">Appearance</string> <string name="appearance">Appearance</string>
<string name="shortcuts">Shortcuts</string>
<string name="app_lock">App lock</string> <string name="app_lock">App lock</string>
<string name="minimum_length_4">The length must not be less than 4</string> <string name="minimum_length_4">The length must not be less than 4</string>
<string name="leave_empty_to_remain_unchanged">Leave empty to remain unchanged</string> <string name="leave_empty_to_remain_unchanged">Leave empty to remain unchanged</string>