Skip to content

Commit 524cc45

Browse files
Implement disable screenshot sounds
1 parent e5d1632 commit 524cc45

File tree

13 files changed

+168
-13
lines changed

13 files changed

+168
-13
lines changed

DisableSounds/build.gradle.kts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,12 @@ android {
1111
targetSdk = 36
1212
}
1313
}
14+
15+
dependencies {
16+
// fragment-ktx is included as transitive dependency through preference-ktx
17+
// the transitive dependency is a lower version though, which allows minSdk 17,
18+
// while explicit mention with the latest version forced minSdk 21
19+
//implementation(libs.androidx.fragment.ktx)
20+
implementation(libs.androidx.preference.ktx)
21+
implementation(libs.kotlinx.coroutines.guava)
22+
}
Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,31 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<manifest
3-
xmlns:android="http://schemas.android.com/apk/res/android">
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
43

5-
<application android:label="DisableSounds">
4+
<application android:label="@string/app_name">
5+
<activity
6+
android:name=".SettingsActivity"
7+
android:exported="true"
8+
android:excludeFromRecents="true"
9+
android:label="@string/title_activity_settings"
10+
android:theme="@style/AppTheme">
11+
<intent-filter>
12+
<action android:name="android.intent.action.MAIN" />
13+
<category android:name="de.robv.android.xposed.category.MODULE_SETTINGS" />
14+
</intent-filter>
15+
</activity>
16+
617
<meta-data
718
android:name="xposedmodule"
8-
android:value="true"
9-
/>
19+
android:value="true" />
1020
<meta-data
1121
android:name="xposeddescription"
12-
android:value="Disable various system sounds"
13-
/>
22+
android:value="@string/description" />
1423
<meta-data
1524
android:name="xposedminversion"
16-
android:value="53"
17-
/>
25+
android:value="93" />
1826
<meta-data
1927
android:name="xposedscope"
20-
android:resource="@array/scope"
21-
/>
28+
android:resource="@array/scope" />
2229
</application>
2330

2431
</manifest>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
com.programminghoch10.DisableSounds.DisableForcedCameraSoundHook
2+
com.programminghoch10.DisableSounds.DisableScreenshotSoundHook

DisableSounds/src/main/java/com/programminghoch10/DisableSounds/DisableForcedCameraSoundHook.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.programminghoch10.DisableSounds
33
import android.content.res.XResources
44
import android.media.MediaActionSound
55
import android.os.Build
6-
import android.util.Log
76
import de.robv.android.xposed.IXposedHookLoadPackage
87
import de.robv.android.xposed.IXposedHookZygoteInit
98
import de.robv.android.xposed.XC_MethodReplacement
@@ -12,7 +11,6 @@ import de.robv.android.xposed.callbacks.XC_LoadPackage
1211

1312
class DisableForcedCameraSoundHook : IXposedHookLoadPackage, IXposedHookZygoteInit {
1413
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
15-
Log.d(TAG, "handleLoadPackage: loaded ${this::class.java.simpleName} with package ${lpparam.packageName}")
1614
if (lpparam.packageName == "android") {
1715
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
1816
val AudioServiceClass = XposedHelpers.findClass("com.android.server.audio.AudioService", lpparam.classLoader)
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.programminghoch10.DisableSounds
2+
3+
import android.annotation.SuppressLint
4+
import android.content.Context
5+
import android.media.MediaActionSound
6+
import android.os.Build
7+
import com.google.common.util.concurrent.Futures
8+
import de.robv.android.xposed.IXposedHookLoadPackage
9+
import de.robv.android.xposed.XC_MethodHook
10+
import de.robv.android.xposed.XC_MethodReplacement
11+
import de.robv.android.xposed.XSharedPreferences
12+
import de.robv.android.xposed.XposedHelpers
13+
import de.robv.android.xposed.callbacks.XC_LoadPackage
14+
15+
class DisableScreenshotSoundHook : IXposedHookLoadPackage {
16+
@SuppressLint("ObsoleteSdkInt")
17+
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
18+
if (lpparam.packageName != "com.android.systemui") return
19+
val sharedPreferences = XSharedPreferences(BuildConfig.APPLICATION_ID, SHARED_PREFERENCES_NAME)
20+
if (!sharedPreferences.getBoolean("screenshot", false)) return
21+
22+
when {
23+
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> XposedHelpers.findAndHookMethod(
24+
"com.android.systemui.screenshot.ScreenshotSoundControllerImpl",
25+
lpparam.classLoader,
26+
"playScreenshotSoundAsync",
27+
XC_MethodReplacement.DO_NOTHING,
28+
)
29+
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ->
30+
// TODO: check if inlined by r8 on 33
31+
XposedHelpers.findAndHookMethod(
32+
"com.android.systemui.screenshot.ScreenshotController",
33+
lpparam.classLoader,
34+
"playCameraSound",
35+
XC_MethodReplacement.DO_NOTHING,
36+
)
37+
38+
}
39+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
40+
val ScreenshotControllerClass = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
41+
XposedHelpers.findClass("com.android.systemui.screenshot.ScreenshotController", lpparam.classLoader)
42+
} else {
43+
XposedHelpers.findClass("com.android.systemui.screenshot.GlobalScreenshot", lpparam.classLoader)
44+
}
45+
46+
var replacementDummy: Any = MediaActionSoundDummy()
47+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) replacementDummy = Futures.immediateFuture(replacementDummy)
48+
49+
XposedHelpers.findAndHookConstructor(
50+
ScreenshotControllerClass, Context::class.java, object : XC_MethodHook() {
51+
override fun afterHookedMethod(param: MethodHookParam) {
52+
XposedHelpers.setObjectField(
53+
param.thisObject, "mCameraSound", replacementDummy
54+
)
55+
}
56+
})
57+
}
58+
}
59+
60+
class MediaActionSoundDummy : MediaActionSound() {
61+
override fun load(soundName: Int) {}
62+
override fun play(soundName: Int) {}
63+
override fun release() {}
64+
}
65+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.programminghoch10.DisableSounds
2+
3+
import android.annotation.SuppressLint
4+
import android.os.Bundle
5+
import androidx.fragment.app.FragmentActivity
6+
import androidx.preference.PreferenceFragmentCompat
7+
8+
val SHARED_PREFERENCES_NAME = "disable_sounds"
9+
10+
class SettingsActivity : FragmentActivity() {
11+
override fun onCreate(savedInstanceState: Bundle?) {
12+
super.onCreate(savedInstanceState)
13+
setContentView(R.layout.settings_activity)
14+
if (savedInstanceState == null) {
15+
supportFragmentManager.beginTransaction().replace(R.id.settings, SettingsFragment()).commit()
16+
}
17+
actionBar?.setDisplayHomeAsUpEnabled(true)
18+
}
19+
20+
override fun onNavigateUp(): Boolean {
21+
finish()
22+
return true
23+
}
24+
25+
class SettingsFragment : PreferenceFragmentCompat() {
26+
@SuppressLint("WorldReadableFiles")
27+
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
28+
preferenceManager.sharedPreferencesName = SHARED_PREFERENCES_NAME
29+
preferenceManager.sharedPreferencesMode = MODE_WORLD_READABLE
30+
setPreferencesFromResource(R.xml.root_preferences, rootKey)
31+
}
32+
}
33+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:layout_width="match_parent"
3+
android:layout_height="match_parent"
4+
android:theme="@style/AppTheme.Edge2EdgeFix">
5+
6+
<FrameLayout
7+
android:id="@+id/settings"
8+
android:layout_width="match_parent"
9+
android:layout_height="match_parent" />
10+
</LinearLayout>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<resources>
3+
4+
<style name="AppTheme" parent="@android:style/Theme.DeviceDefault.Settings" />
5+
</resources>

DisableSounds/src/main/res/values/arrays.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<resources>
33
<string-array name="scope">
44
<item>android</item>
5+
<item>com.android.systemui</item>
56
<item>org.lineageos.aperture</item>
67
</string-array>
78
</resources>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<resources>
3+
<string name="title_activity_settings">DisableSounds Configuration</string>
4+
<string name="app_name">DisableSounds</string>
5+
<string name="description">Disable various system sounds</string>
6+
<string name="disable_screenshot_sound_title">Disable screenshot sound</string>
7+
<string name="disable_screenshot_sound_description">@null</string>
8+
</resources>

0 commit comments

Comments
 (0)