diff --git a/assets/meta.xml b/assets/meta.xml
index 690182124..3120b9f8c 100644
--- a/assets/meta.xml
+++ b/assets/meta.xml
@@ -102,6 +102,9 @@
+
+
+
@@ -159,7 +162,7 @@
-
+
@@ -197,6 +200,8 @@
+
+
diff --git a/src/android/location/ILocationListener.java b/src/android/location/ILocationListener.java
index 1ce0b5b7e..ffbf60ac0 100644
--- a/src/android/location/ILocationListener.java
+++ b/src/android/location/ILocationListener.java
@@ -5,9 +5,9 @@
public interface ILocationListener extends android.os.IInterface {
void onLocationChanged(Location location);
- void onProviderDisabled(String provider);
+ void onStatusChanged(String provider, int status, Bundle extras);
void onProviderEnabled(String provider);
- void onStatusChanged(String provider, int status, Bundle extras);
+ void onProviderDisabled(String provider);
}
diff --git a/src/biz/bokhorst/xprivacy/XPrivacy.java b/src/biz/bokhorst/xprivacy/XPrivacy.java
index d786cf4f8..5f4286055 100644
--- a/src/biz/bokhorst/xprivacy/XPrivacy.java
+++ b/src/biz/bokhorst/xprivacy/XPrivacy.java
@@ -113,6 +113,9 @@ public void initZygote(StartupParam startupParam) throws Throwable {
// System properties
hookAll(XSystemProperties.getInstances());
+ // Telephony registry
+ hookAll(XTelephonyRegistry.getInstances());
+
// Thread
hookAll(XThread.getInstances());
diff --git a/src/biz/bokhorst/xprivacy/XTelephonyManager.java b/src/biz/bokhorst/xprivacy/XTelephonyManager.java
index 30f1edd44..59321714e 100644
--- a/src/biz/bokhorst/xprivacy/XTelephonyManager.java
+++ b/src/biz/bokhorst/xprivacy/XTelephonyManager.java
@@ -114,6 +114,8 @@ public static List getInstances(Object instance) {
listHook.add(new XTelephonyManager(Methods.getSubscriberId, PrivacyManager.cPhone, className));
listHook.add(new XTelephonyManager(Methods.getVoiceMailAlphaTag, PrivacyManager.cPhone, className));
listHook.add(new XTelephonyManager(Methods.getVoiceMailNumber, PrivacyManager.cPhone, className));
+
+ listHook.add(new XTelephonyManager(Methods.listen, PrivacyManager.cLocation, className));
listHook.add(new XTelephonyManager(Methods.listen, PrivacyManager.cPhone, className));
// No permissions required
diff --git a/src/biz/bokhorst/xprivacy/XTelephonyRegistry.java b/src/biz/bokhorst/xprivacy/XTelephonyRegistry.java
new file mode 100644
index 000000000..5b6bc4840
--- /dev/null
+++ b/src/biz/bokhorst/xprivacy/XTelephonyRegistry.java
@@ -0,0 +1,189 @@
+package biz.bokhorst.xprivacy;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import com.android.internal.telephony.IPhoneStateListener;
+
+import android.content.Context;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.telephony.CellInfo;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.util.Log;
+
+import de.robv.android.xposed.XC_MethodHook.MethodHookParam;
+
+import static de.robv.android.xposed.XposedHelpers.findField;
+
+public class XTelephonyRegistry extends XHook {
+ private Methods mMethod;
+ private static final Map mListener = new WeakHashMap();
+
+ private XTelephonyRegistry(Methods method, String restrictionName) {
+ super(restrictionName, method.name(), String.format("Srv.%s", method.name()));
+ mMethod = method;
+ }
+
+ private XTelephonyRegistry(Methods method, String restrictionName, int sdk) {
+ super(restrictionName, method.name(), String.format("Srv.%s", method.name()), sdk);
+ mMethod = method;
+ }
+
+ public String getClassName() {
+ return "com.android.server.TelephonyRegistry";
+ }
+
+ // @formatter:off
+
+ // public void listen(String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow)
+ // frameworks/base/services/java/com/android/server/TelephonyRegistry.java
+ // http://developer.android.com/reference/android/telephony/TelephonyManager.html
+
+ // @formatter:on
+
+ private enum Methods {
+ listen
+ };
+
+ public static List getInstances() {
+ List listHook = new ArrayList();
+ listHook.add(new XTelephonyRegistry(Methods.listen, PrivacyManager.cLocation));
+ listHook.add(new XTelephonyRegistry(Methods.listen, PrivacyManager.cPhone));
+ return listHook;
+ }
+
+ @Override
+ protected void before(MethodHookParam param) throws Throwable {
+ if (mMethod == Methods.listen)
+ replacePhoneStateListener(param);
+ else
+ Util.log(this, Log.WARN, "Unknown method=" + param.method.getName());
+ }
+
+ private void replacePhoneStateListener(MethodHookParam param) throws Throwable {
+ if (param.args.length > 2 && param.args[1] != null) {
+ IPhoneStateListener listener = (IPhoneStateListener) param.args[1];
+ int event = (Integer) param.args[2];
+ if (listener != null)
+ if (isRestricted(param)) {
+ if (event == PhoneStateListener.LISTEN_NONE) {
+ // Remove
+ synchronized (mListener) {
+ XIPhoneStateListener xlistener = mListener.get(listener);
+ if (xlistener == null)
+ Util.log(this, Log.WARN, "Not found count=" + mListener.size());
+ else {
+ param.args[1] = xlistener;
+ mListener.remove(listener);
+ }
+ }
+ } else {
+ // Replace
+ XIPhoneStateListener xListener = new XIPhoneStateListener(listener);
+ synchronized (mListener) {
+ mListener.put(listener, xListener);
+ Util.log(this, Log.INFO, "Added count=" + mListener.size());
+ }
+ param.args[1] = xListener;
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void after(MethodHookParam param) throws Throwable {
+ // Do nothing
+ }
+
+ @Override
+ protected boolean isRestricted(MethodHookParam param) throws Throwable {
+ Context context = null;
+
+ try {
+ Field fieldContext = findField(param.thisObject.getClass(), "mContext");
+ context = (Context) fieldContext.get(param.thisObject);
+ } catch (NoSuchFieldError ex) {
+ } catch (Throwable ex) {
+ Util.bug(this, ex);
+ }
+
+ int uid = Binder.getCallingUid();
+ return getRestricted(context, uid, true);
+ }
+
+ private class XIPhoneStateListener implements IPhoneStateListener {
+ private IPhoneStateListener mListener;
+
+ public XIPhoneStateListener(IPhoneStateListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void onCallForwardingIndicatorChanged(boolean cfi) {
+ mListener.onCallForwardingIndicatorChanged(cfi);
+ }
+
+ @Override
+ public void onCallStateChanged(int state, String incomingNumber) {
+ mListener.onCallStateChanged(state,
+ (String) PrivacyManager.getDefacedProp(Binder.getCallingUid(), "PhoneNumber"));
+ }
+
+ @Override
+ public void onCellInfoChanged(List cellInfo) {
+ mListener.onCellInfoChanged(new ArrayList());
+ }
+
+ @Override
+ public void onCellLocationChanged(Bundle location) {
+ mListener.onCellLocationChanged(new Bundle());
+ }
+
+ @Override
+ public void onDataActivity(int direction) {
+ mListener.onDataActivity(direction);
+ }
+
+ @Override
+ public void onDataConnectionStateChanged(int state, int networkType) {
+ mListener.onDataConnectionStateChanged(state, networkType);
+ }
+
+ @Override
+ public void onMessageWaitingIndicatorChanged(boolean mwi) {
+ mListener.onMessageWaitingIndicatorChanged(mwi);
+ }
+
+ @Override
+ public void onServiceStateChanged(ServiceState serviceState) {
+ mListener.onServiceStateChanged(serviceState);
+ }
+
+ @Override
+ public void onSignalStrengthChanged(int asu) {
+ mListener.onSignalStrengthChanged(asu);
+ }
+
+ @Override
+ public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+ mListener.onSignalStrengthsChanged(signalStrength);
+ }
+
+ @Override
+ public void onOtaspChanged(int otaspMode) {
+ mListener.onOtaspChanged(otaspMode);
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return mListener.asBinder();
+ }
+ }
+}
diff --git a/src/com/android/internal/telephony/IPhoneStateListener.java b/src/com/android/internal/telephony/IPhoneStateListener.java
new file mode 100644
index 000000000..1cce84ce4
--- /dev/null
+++ b/src/com/android/internal/telephony/IPhoneStateListener.java
@@ -0,0 +1,34 @@
+package com.android.internal.telephony;
+
+import java.util.List;
+
+import android.os.Bundle;
+import android.telephony.CellInfo;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+
+public interface IPhoneStateListener extends android.os.IInterface {
+ void onServiceStateChanged(ServiceState serviceState);
+
+ void onSignalStrengthChanged(int asu);
+
+ void onMessageWaitingIndicatorChanged(boolean mwi);
+
+ void onCallForwardingIndicatorChanged(boolean cfi);
+
+ // we use bundle here instead of CellLocation so it can get the right
+ // subclass
+ void onCellLocationChanged(Bundle location);
+
+ void onCallStateChanged(int state, String incomingNumber);
+
+ void onDataConnectionStateChanged(int state, int networkType);
+
+ void onDataActivity(int direction);
+
+ void onSignalStrengthsChanged(SignalStrength signalStrength);
+
+ void onOtaspChanged(int otaspMode);
+
+ void onCellInfoChanged(List cellInfo);
+}