如何在Android源码中访问setPreferredNetworkType

发布于 2024-10-26 20:12:12 字数 2619 浏览 2 评论 0原文

我有一个问题想问您,我正在尝试在 Android 手机上选择首选网络类型。 您可以通过执行以下步骤来完成:

  1. 拨打##4636##
  2. 选择“电话信息”
  3. 转到底部
  4. 在菜单上选择首选网络类型

因此在对源代码进行了一些搜索之后我找到了正确的类:Phone.java in (\frameworks\base\telephony\java\com\android\internal\telephony)

所以有了 Vinay 的好提示: 如何在 Android 上禁用移动数据 谁在使用java反射来访问隐藏类,我也尝试这样做:

Method setPrefNetmethod;
Class telephonyManagerClass;
Object ITelephonyStub;
Class ITelephonyClass;

TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
telephonyManagerClass = Class.forName(telephonyManager.getClass().getName());
Method getITelephonyMethod = telephonyManagerClass.getDeclaredMethod("getITelephony");
getITelephonyMethod.setAccessible(true);
ITelephonyStub = getITelephonyMethod.invoke(telephonyManager);
ITelephonyClass = Class.forName(ITelephonyStub.getClass().getName());

setPrefNetmethod = ITelephonyClass.getDeclaredMethod("setPreferredNetworkType",new Class[] { Integer.class, Message.class });

Message response = Message.obtain();
setPrefNetmethod.setAccessible(false);

setPrefNetmethod.invoke(ITelephonyStub, new Object[] { network_mode, response });

但问题是我在DDMS上遇到了这个错误:

03-25 18:18:45.937: 警告/系统错误(2989):java.lang.NoSuchMethodException:setPreferredNetworkType 03-25 18:18:45.937: WARN/System.err(2989): 在 java.lang.ClassCache.findMethodByName(ClassCache.java:308)

那么你有想法访问setPreferredNetworkType或以编程方式选择我的首选网络类型吗?

有关信息(在 RILConstants.java 中):

/* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
int NETWORK_MODE_WCDMA_PREF     = 0; /* GSM/WCDMA (WCDMA preferred) */
int NETWORK_MODE_GSM_ONLY       = 1; /* GSM only */
int NETWORK_MODE_WCDMA_ONLY     = 2; /* WCDMA only */
int NETWORK_MODE_GSM_UMTS       = 3; /* GSM/WCDMA (auto mode, according to PRL)
                                        AVAILABLE Application Settings menu*/
int NETWORK_MODE_CDMA           = 4; /* CDMA and EvDo (auto mode, according to PRL)
                                        AVAILABLE Application Settings menu*/
int NETWORK_MODE_CDMA_NO_EVDO   = 5; /* CDMA only */
int NETWORK_MODE_EVDO_NO_CDMA   = 6; /* EvDo only */
int NETWORK_MODE_GLOBAL         = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL)
                                        AVAILABLE Application Settings menu*/
int PREFERRED_NETWORK_MODE      = NETWORK_MODE_WCDMA_PREF;

I have a question for you, I am trying to select the Preferred Network Type on my Android phone.
As you can do by doing following steps:

  1. Dial ##4636##
  2. Choose "Phone Information"
  3. Go bottom
  4. Choose preferred Network Type on menu

So after some searches on the source code I found the right class: Phone.java in (\frameworks\base\telephony\java\com\android\internal\telephony)

So with the nice tips of Vinay: How to disable Mobile Data on Android
Who is using java reflexion to acces to hidden classes, I tried too by doing:

Method setPrefNetmethod;
Class telephonyManagerClass;
Object ITelephonyStub;
Class ITelephonyClass;

TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
telephonyManagerClass = Class.forName(telephonyManager.getClass().getName());
Method getITelephonyMethod = telephonyManagerClass.getDeclaredMethod("getITelephony");
getITelephonyMethod.setAccessible(true);
ITelephonyStub = getITelephonyMethod.invoke(telephonyManager);
ITelephonyClass = Class.forName(ITelephonyStub.getClass().getName());

setPrefNetmethod = ITelephonyClass.getDeclaredMethod("setPreferredNetworkType",new Class[] { Integer.class, Message.class });

Message response = Message.obtain();
setPrefNetmethod.setAccessible(false);

setPrefNetmethod.invoke(ITelephonyStub, new Object[] { network_mode, response });

But the problem is that I have this error on DDMS:

03-25 18:18:45.937:
WARN/System.err(2989): java.lang.NoSuchMethodException: setPreferredNetworkType
03-25 18:18:45.937: WARN/System.err(2989): at java.lang.ClassCache.findMethodByName(ClassCache.java:308)

So do you have an idea to access setPreferredNetworkType or choose programmaticaly my preferred network type ?

For information (In RILConstants.java) :

/* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
int NETWORK_MODE_WCDMA_PREF     = 0; /* GSM/WCDMA (WCDMA preferred) */
int NETWORK_MODE_GSM_ONLY       = 1; /* GSM only */
int NETWORK_MODE_WCDMA_ONLY     = 2; /* WCDMA only */
int NETWORK_MODE_GSM_UMTS       = 3; /* GSM/WCDMA (auto mode, according to PRL)
                                        AVAILABLE Application Settings menu*/
int NETWORK_MODE_CDMA           = 4; /* CDMA and EvDo (auto mode, according to PRL)
                                        AVAILABLE Application Settings menu*/
int NETWORK_MODE_CDMA_NO_EVDO   = 5; /* CDMA only */
int NETWORK_MODE_EVDO_NO_CDMA   = 6; /* EvDo only */
int NETWORK_MODE_GLOBAL         = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL)
                                        AVAILABLE Application Settings menu*/
int PREFERRED_NETWORK_MODE      = NETWORK_MODE_WCDMA_PREF;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

北城孤痞 2024-11-02 20:12:12

这是一个关于如何访问内部 API 的很好的指南:
https://devmaze.wordpress。 com/2011/01/18/using-com-android-internal-part-1-introduction/

根据我自己的经验,我可以告诉你访问通常可以工作,但你会得到一个运行时异常,因为只有系统应用程序有设置首选网络类型的权限。

这意味着您的应用程序还必须安装在系统文件夹中,并且必须使用系统密钥进行签名,这是问题的关键......

Here's a nice guide how to access the internal API:
https://devmaze.wordpress.com/2011/01/18/using-com-android-internal-part-1-introduction/

From own experience I can tell you that the access generally works but you will get a runtime exception because only system apps have permissions for setting Preferred Network Type.

This means your app also has to be installed in the system folder AND has to be signed with system key, which is the crux of the matter....

ㄟ。诗瑗 2024-11-02 20:12:12

首先,您必须在清单中添加以下权限;

<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" tools:ignore="ProtectedPermissions"/>

然后使用下面的代码设置首选网络(请注意,您的应用程序必须经过 OEM 签名 [系统权限] 才能运行);

public boolean setPreferredNetworkType(int networkType, int timeout) {
    Boolean result = false;
    try {
        TelephonyManager telephonyManager = (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
        final Method getPreferredNetworkType = telephonyManager.getClass().getDeclaredMethod("getPreferredNetworkType", int.class);
        final Method setPreferredNetworkType = telephonyManager.getClass().getDeclaredMethod("setPreferredNetworkType", int.class, int.class);
        final Method getSubId = telephonyManager.getClass().getDeclaredMethod("getSubId");
        getPreferredNetworkType.setAccessible(true);
        setPreferredNetworkType.setAccessible(true);
        getSubId.setAccessible(true);
        Integer currentNetworkType = (Integer) getPreferredNetworkType.invoke(telephonyManager, getSubId.invoke(telephonyManager));
        if (currentNetworkType != networkType) {
            setPreferredNetworkType.invoke(telephonyManager, getSubId.invoke(telephonyManager), networkType);
            while (timeout > 0) {
                currentNetworkType = (Integer) getPreferredNetworkType.invoke(telephonyManager, getSubId.invoke(telephonyManager));
                if (currentNetworkType == networkType) {
                    result = true;
                    break;
                }
                try {
                    Thread.sleep(THREAD_WAIT_TIMEOUT_IN_MS);
                } catch (InterruptedException e) {
                }
                timeout -= THREAD_WAIT_TIMEOUT_IN_MS;
            }
        } else {
            result = true;
        }
    } catch (SecurityException se) {
    } catch (Exception e) {
    }

    return result;
}

在上面,您可以使用 RILConstants.java 整数值作为“networkType”。

First you have to add below permission in your manifest;

<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" tools:ignore="ProtectedPermissions"/>

Then use below code to set preferred network (please note your app has to be OEM signed [System permission] for below to work);

public boolean setPreferredNetworkType(int networkType, int timeout) {
    Boolean result = false;
    try {
        TelephonyManager telephonyManager = (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
        final Method getPreferredNetworkType = telephonyManager.getClass().getDeclaredMethod("getPreferredNetworkType", int.class);
        final Method setPreferredNetworkType = telephonyManager.getClass().getDeclaredMethod("setPreferredNetworkType", int.class, int.class);
        final Method getSubId = telephonyManager.getClass().getDeclaredMethod("getSubId");
        getPreferredNetworkType.setAccessible(true);
        setPreferredNetworkType.setAccessible(true);
        getSubId.setAccessible(true);
        Integer currentNetworkType = (Integer) getPreferredNetworkType.invoke(telephonyManager, getSubId.invoke(telephonyManager));
        if (currentNetworkType != networkType) {
            setPreferredNetworkType.invoke(telephonyManager, getSubId.invoke(telephonyManager), networkType);
            while (timeout > 0) {
                currentNetworkType = (Integer) getPreferredNetworkType.invoke(telephonyManager, getSubId.invoke(telephonyManager));
                if (currentNetworkType == networkType) {
                    result = true;
                    break;
                }
                try {
                    Thread.sleep(THREAD_WAIT_TIMEOUT_IN_MS);
                } catch (InterruptedException e) {
                }
                timeout -= THREAD_WAIT_TIMEOUT_IN_MS;
            }
        } else {
            result = true;
        }
    } catch (SecurityException se) {
    } catch (Exception e) {
    }

    return result;
}

In above you can use the RILConstants.java Integer values as 'networkType'.

十雾 2024-11-02 20:12:12

您可以尝试这篇文章:http://www.josemauricio.net/?p=486

它使用这些 AT 命令:

KitKat: echo "AT^SYSCONFIG=13,1,1,2\r" > /dev/smd0

Lollipop: echo "AT+WS46=12\r" > /dev/umts_at0

主要问题之一是找到设备使用的正确命令和串行端口。

You can try this post: http://www.josemauricio.net/?p=486

It's using these AT commands:

KitKat: echo "AT^SYSCONFIG=13,1,1,2\r" > /dev/smd0

Lollipop: echo "AT+WS46=12\r" > /dev/umts_at0

One of the main issues, is founding the right command and serial port your device uses.

书信已泛黄 2024-11-02 20:12:12

为此,您的应用必须使用系统密钥进行签名或拥有运营商权限。否则应用程序将抛出
java.lang.SecurityException: 无修改权限或运营商权限。

我的应用程序在 Android 5.1 Lollipop(API 22) 上运行,并使用系统密钥进行签名,因此这是我可以确定的唯一配置有效。我无法确认运营商特权方法。

AndroidManifest.xml

将此权限添加到您的应用清单中。如果您使用的是 Android Studio,它可能会将这一行标记为错误,因为只有系统应用程序才能拥有此权限。如果您可以使用系统密钥签署您的应用程序,请不用担心。

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

获取首选网络

返回值在 RILConstants.java 中定义,例如 RILConstants.NETWORK_MODE_WCDMA_PREF

public int getPreferredNetwork() {
    Method method = getHiddenMethod("getPreferredNetworkType", TelephonyManager.class, null);
    int preferredNetwork = -1000;
    try {
        preferredNetwork = (int) method.invoke(mTelephonyManager);
        Log.i(TAG, "Preferred Network is ::: " + preferredNetwork);
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }

    return preferredNetwork;
}

设置首选方法。

该参数必须基于RILConstants.java,例如:RILConstants.NETWORK_MODE_LTE_ONLY

public void setPreferredNetwork(int networkType) {
    try {
        Method setPreferredNetwork = getHiddenMethod("setPreferredNetworkType",
                TelephonyManager.class, new Class[] {int.class});
        Boolean success = (Boolean)setPreferredNetwork.invoke(mTelephonyManager,
                networkType);
        Log.i(TAG, "Could set Network Type ::: " + (success.booleanValue() ? "YES" : "NO"));
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

这是访问隐藏API 方法的实用方法。

/**
 * Get a hidden method instance from a class
 * @param methodName The name of the method to be taken from the class
 * @param fromClass The name of the class that has the method
 * @return A Method instance that can be invoked
 */
public Method getHiddenMethod(String methodName, Class fromClass, Class[] params) {
    Method method = null;
    try {
        Class clazz = Class.forName(fromClass.getName());
        method = clazz.getMethod(methodName, params);
        method.setAccessible(true);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }

    return method;
}

For this to work, your app must be signed with the system key or have carrier privilege. Otherwise the app will throw
java.lang.SecurityException: No modify permission or carrier privilege.

My app runs on Android 5.1 Lollipop(API 22) and is signed with the system key, so this is the only configuration I can confirm for sure that works. I can't confirm the carrier privilege approach.

AndroidManifest.xml

Add this permission to your app manifest. If you are using Android Studio, it will probably mark this line as an error because only system apps can have this permission. If you can sign your app with the system keys, don't worry.

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

Get Preferred Network

The return is defined in RILConstants.java, e.g. RILConstants.NETWORK_MODE_WCDMA_PREF

public int getPreferredNetwork() {
    Method method = getHiddenMethod("getPreferredNetworkType", TelephonyManager.class, null);
    int preferredNetwork = -1000;
    try {
        preferredNetwork = (int) method.invoke(mTelephonyManager);
        Log.i(TAG, "Preferred Network is ::: " + preferredNetwork);
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }

    return preferredNetwork;
}

Set Preferred Method.

The parameter must be based on RILConstants.java, e.g.: RILConstants.NETWORK_MODE_LTE_ONLY

public void setPreferredNetwork(int networkType) {
    try {
        Method setPreferredNetwork = getHiddenMethod("setPreferredNetworkType",
                TelephonyManager.class, new Class[] {int.class});
        Boolean success = (Boolean)setPreferredNetwork.invoke(mTelephonyManager,
                networkType);
        Log.i(TAG, "Could set Network Type ::: " + (success.booleanValue() ? "YES" : "NO"));
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

This is an utility method to access the hidden API methods.

/**
 * Get a hidden method instance from a class
 * @param methodName The name of the method to be taken from the class
 * @param fromClass The name of the class that has the method
 * @return A Method instance that can be invoked
 */
public Method getHiddenMethod(String methodName, Class fromClass, Class[] params) {
    Method method = null;
    try {
        Class clazz = Class.forName(fromClass.getName());
        method = clazz.getMethod(methodName, params);
        method.setAccessible(true);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }

    return method;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文