summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/build.gradle3
-rw-r--r--app/src/main/AndroidManifest.xml36
-rw-r--r--app/src/main/aidl/org/eu/zajc/xheadset/IXHeadsetStateService.aidl5
-rw-r--r--app/src/main/assets/xposed_init2
-rw-r--r--app/src/main/java/org/eu/zajc/xheadset/XHeadsetModule.java (renamed from app/src/main/java/org/eu/zajc/xheadset/XHeadset.java)26
-rw-r--r--app/src/main/java/org/eu/zajc/xheadset/XHeadsetStateCommunicator.java57
-rw-r--r--app/src/main/java/org/eu/zajc/xheadset/XHeadsetStateService.java45
-rw-r--r--app/src/main/java/org/eu/zajc/xheadset/XHeadsetTile.java31
-rw-r--r--app/src/main/res/drawable/headset.xml16
-rw-r--r--app/src/main/res/drawable/speaker.xml13
10 files changed, 207 insertions, 27 deletions
diff --git a/app/build.gradle b/app/build.gradle
index f98f370..8590326 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -18,6 +18,9 @@ android {
18 lintOptions { 18 lintOptions {
19 abortOnError false 19 abortOnError false
20 } 20 }
21 defaultConfig {
22 vectorDrawables.useSupportLibrary = true
23 }
21} 24}
22 25
23repositories { 26repositories {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index bfc3c5e..76a7b24 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,16 +1,26 @@
1<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" 1<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="org.eu.zajc.xheadset">
2 package="org.eu.zajc.xheadset">
3 2
4 <application android:label="Headset Enforcer"> 3 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
5 <meta-data
6 android:name="xposedmodule"
7 android:value="true" />
8 <meta-data
9 android:name="xposeddescription"
10 android:value="This Xposed module allows you to manually override the headphone jack detection of an Android device." />
11 <meta-data
12 android:name="xposedminversion"
13 android:value="53" />
14 </application>
15 4
5 <application android:label="Headset Enforcer">
6
7 <meta-data android:name="xposedmodule" android:value="true" />
8 <meta-data android:name="xposeddescription" android:value="An Xposed module that fixes broken headphone detection using software" />
9 <meta-data android:name="xposedminversion" android:value="53" />
10 <meta-data android:name="android.service.quicksettings.TOGGLEABLE_TILE" android:value="true" />
11
12 <service android:name=".XHeadsetTile" android:icon="@drawable/headset" android:label="Headset" android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
13 <intent-filter>
14 <action android:name="android.service.quicksettings.action.QS_TILE" />
15 </intent-filter>
16 </service>
17
18 <service android:name=".XHeadsetStateService" android:exported="true">
19 <intent-filter>
20 <action android:name="org.eu.zajc.xheadset.XHeadsetStateService.BIND" />
21 <category android:name="android.intent.category.DEFAULT" />
22 </intent-filter>
23 </service>
24
25 </application>
16</manifest> 26</manifest>
diff --git a/app/src/main/aidl/org/eu/zajc/xheadset/IXHeadsetStateService.aidl b/app/src/main/aidl/org/eu/zajc/xheadset/IXHeadsetStateService.aidl
new file mode 100644
index 0000000..ca556bb
--- /dev/null
+++ b/app/src/main/aidl/org/eu/zajc/xheadset/IXHeadsetStateService.aidl
@@ -0,0 +1,5 @@
1package org.eu.zajc.xheadset;
2interface IXHeadsetStateService {
3 boolean isEnabled();
4 boolean setEnabled(boolean enabled);
5}
diff --git a/app/src/main/assets/xposed_init b/app/src/main/assets/xposed_init
index 18c2324..a00c3e8 100644
--- a/app/src/main/assets/xposed_init
+++ b/app/src/main/assets/xposed_init
@@ -1 +1 @@
org.eu.zajc.xheadset.XHeadset org.eu.zajc.xheadset.XHeadsetModule
diff --git a/app/src/main/java/org/eu/zajc/xheadset/XHeadset.java b/app/src/main/java/org/eu/zajc/xheadset/XHeadsetModule.java
index 19eddc4..4889aa7 100644
--- a/app/src/main/java/org/eu/zajc/xheadset/XHeadset.java
+++ b/app/src/main/java/org/eu/zajc/xheadset/XHeadsetModule.java
@@ -1,25 +1,29 @@
1package org.eu.zajc.xheadset; 1package org.eu.zajc.xheadset;
2 2
3import android.graphics.Color; 3import android.util.*;
4import android.widget.TextView; 4import android.app.*;
5import android.widget.*;
5 6
6import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; 7import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
7import de.robv.android.xposed.IXposedHookLoadPackage; 8import de.robv.android.xposed.*;
8import de.robv.android.xposed.XC_MethodHook;
9import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; 9import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
10import android.util.Log;
11 10
12public class XHeadset implements IXposedHookLoadPackage extends TileService { 11public class XHeadsetModule implements IXposedHookLoadPackage {
13 12
14 @Override 13 @Override
15 public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable { 14 public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
16 15 final XHeadsetStateCommunicator comm = new XHeadsetStateCommunicator();
17 if (lpparam.packageName.equals("android")) { 16 if (lpparam.packageName.equals("android")) {
18 findAndHookMethod("com.android.server.WiredAccessoryManager", lpparam.classLoader, "updateLocked", String.class, int.class, new XC_MethodHook() { 17 findAndHookMethod("com.android.server.WiredAccessoryManager", lpparam.classLoader, "updateLocked", String.class, int.class, new XC_MethodHook() {
19 @Override 18 @Override
20 protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 19 protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
21 Log.e("XHeadsetYHRTG", "params: " + param.args[0] + " " + param.args[1]); 20 comm.bind(AndroidAppHelper.currentApplication());
22 param.args[1] = (int) (1 << 1); 21 if (comm.isEnabled()) {
22 Log.e("XHeadset", "Spoofing headphone state");
23 param.args[1] = (int) (1 << 1);
24 } else {
25 Log.e("XHeadset", "Not spoofing headphone state");
26 }
23 } 27 }
24 }); 28 });
25 } else if (lpparam.packageName.equals("com.android.systemui")) { 29 } else if (lpparam.packageName.equals("com.android.systemui")) {
@@ -34,8 +38,4 @@ public class XHeadset implements IXposedHookLoadPackage extends TileService {
34 } 38 }
35 } 39 }
36 40
37 @Override
38 public void onClick() {
39 Log.e("XHeadsetYHRTG", "clicked");
40 }
41} 41}
diff --git a/app/src/main/java/org/eu/zajc/xheadset/XHeadsetStateCommunicator.java b/app/src/main/java/org/eu/zajc/xheadset/XHeadsetStateCommunicator.java
new file mode 100644
index 0000000..b028b8d
--- /dev/null
+++ b/app/src/main/java/org/eu/zajc/xheadset/XHeadsetStateCommunicator.java
@@ -0,0 +1,57 @@
1package org.eu.zajc.xheadset;
2
3import java.io.*;
4import android.os.*;
5import android.util.*;
6import android.content.*;
7import android.app.*;
8
9public class XHeadsetStateCommunicator {
10
11 protected IXHeadsetStateService service = null;
12
13 public void bind(Context context) {
14 if (service == null)
15 context.bindService(createIntent(), connection, Context.BIND_AUTO_CREATE);
16 }
17
18 public static Intent createIntent() {
19 return new Intent("org.eu.zajc.xheadset.XHeadsetStateService.BIND").setPackage("org.eu.zajc.xheadset");
20 }
21
22 public void unbind(Context context) {
23 if (service != null)
24 context.unbindService(connection);
25 }
26
27 public boolean setEnabled(boolean enabled) {
28 try {
29 return service.setEnabled(enabled);
30 } catch (RemoteException e) {
31 Log.e("XHeadset", "An exception has occurred", e);
32 return false;
33 }
34 }
35
36 public boolean isEnabled() {
37 try {
38 return service.isEnabled();
39 } catch (RemoteException e) {
40 Log.e("XHeadset", "An exception has occurred", e);
41 return XHeadsetStateService.DEFAULT_STATE;
42 }
43 }
44
45 private ServiceConnection connection = new ServiceConnection() {
46 @Override
47 public void onServiceConnected(ComponentName name, IBinder service) {
48 XHeadsetStateCommunicator.this.service = IXHeadsetStateService.Stub.asInterface(service);
49 }
50
51 @Override
52 public void onServiceDisconnected(ComponentName name) {
53 XHeadsetStateCommunicator.this.service = null;
54 }
55 };
56
57}
diff --git a/app/src/main/java/org/eu/zajc/xheadset/XHeadsetStateService.java b/app/src/main/java/org/eu/zajc/xheadset/XHeadsetStateService.java
new file mode 100644
index 0000000..d4410f8
--- /dev/null
+++ b/app/src/main/java/org/eu/zajc/xheadset/XHeadsetStateService.java
@@ -0,0 +1,45 @@
1package org.eu.zajc.xheadset;
2
3import java.io.*;
4import android.os.*;
5import android.util.*;
6import android.content.*;
7import android.app.*;
8
9public class XHeadsetStateService extends Service {
10
11 public static final boolean DEFAULT_STATE = false;
12 private static final String PREFS_FILE = "xheadset";
13
14 public SharedPreferences getPrefs() {
15 return this.getPrefs(this);
16 }
17
18 public static SharedPreferences getPrefs(Context context) {
19 return context.getSharedPreferences(PREFS_FILE, MODE_PRIVATE);
20 }
21
22 public static boolean isEnabled(SharedPreferences prefs) {
23 return prefs.getBoolean("state", DEFAULT_STATE);
24 }
25
26 public static boolean setEnabled(SharedPreferences prefs, boolean enabled) {
27 return prefs.edit().putBoolean("state", enabled).commit();
28 }
29
30 @Override
31 public IBinder onBind(Intent intent) {
32 return binder;
33 }
34
35 private final IXHeadsetStateService.Stub binder = new IXHeadsetStateService.Stub() {
36 public boolean isEnabled() {
37 return XHeadsetStateService.isEnabled(getPrefs());
38 }
39
40 public boolean setEnabled(boolean enabled) {
41 return XHeadsetStateService.setEnabled(getPrefs(), enabled);
42 }
43 };
44
45}
diff --git a/app/src/main/java/org/eu/zajc/xheadset/XHeadsetTile.java b/app/src/main/java/org/eu/zajc/xheadset/XHeadsetTile.java
new file mode 100644
index 0000000..b6efe4a
--- /dev/null
+++ b/app/src/main/java/org/eu/zajc/xheadset/XHeadsetTile.java
@@ -0,0 +1,31 @@
1package org.eu.zajc.xheadset;
2
3import android.content.*;
4import android.service.quicksettings.*;
5import android.graphics.drawable.*;
6import android.util.*;
7
8public class XHeadsetTile extends TileService {
9
10 @Override
11 public void onStartListening() {
12 setEnabled(XHeadsetStateService.isEnabled(XHeadsetStateService.getPrefs(this)));
13 }
14
15 @Override
16 public void onClick() {
17 SharedPreferences prefs = XHeadsetStateService.getPrefs(this);
18 boolean oldState = XHeadsetStateService.isEnabled(prefs);
19 if (XHeadsetStateService.setEnabled(prefs, !oldState)) {
20 setEnabled(!oldState);
21 }
22
23 }
24
25 public void setEnabled(boolean enabled) {
26 Tile tile = getQsTile();
27 tile.setIcon(Icon.createWithResource(this, enabled ? R.drawable.headset : R.drawable.speaker));
28 tile.setState(enabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
29 tile.updateTile();
30 }
31}
diff --git a/app/src/main/res/drawable/headset.xml b/app/src/main/res/drawable/headset.xml
new file mode 100644
index 0000000..bfcbe0d
--- /dev/null
+++ b/app/src/main/res/drawable/headset.xml
@@ -0,0 +1,16 @@
1<?xml version="1.0" encoding="utf-8"?>
2<vector xmlns:android="http://schemas.android.com/apk/res/android"
3 android:width="24dp"
4 android:height="24dp"
5 android:viewportWidth="24"
6 android:viewportHeight="24">
7
8 <path
9 android:fillAlpha=".1"
10 android:strokeAlpha=".1"
11 android:strokeWidth="1"
12 android:pathData="M0 0h24v24H0z" />
13 <path
14 android:fillColor="#000000"
15 android:pathData="M12 1c-4.97 0-9 4.03-9 9v7c0 1.66 1.34 3 3 3h3v-8H5v-2c0-3.87 3.13-7 7-7s7 3.13 7 7v2h-4v8h3c1.66 0 3-1.34 3-3v-7c0-4.97-4.03-9-9-9z" />
16</vector>
diff --git a/app/src/main/res/drawable/speaker.xml b/app/src/main/res/drawable/speaker.xml
new file mode 100644
index 0000000..4185aef
--- /dev/null
+++ b/app/src/main/res/drawable/speaker.xml
@@ -0,0 +1,13 @@
1<?xml version="1.0" encoding="utf-8"?>
2<vector xmlns:android="http://schemas.android.com/apk/res/android"
3 android:width="24dp"
4 android:height="24dp"
5 android:viewportWidth="24"
6 android:viewportHeight="24">
7
8 <path
9 android:pathData="M0 0h24v24H0z" />
10 <path
11 android:fillColor="#000000"
12 android:pathData="M17 2H7c-1.1 0-2 0.9-2 2v16c0 1.1 0.9 1.99 2 1.99L17 22c1.1 0 2-0.9 2-2V4c0-1.1-0.9-2-2-2zm-5 2c1.1 0 2 0.9 2 2s-0.9 2-2 2c-1.11 0-2-0.9-2-2s0.89-2 2-2zm0 16c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z" />
13</vector>