Android5.0以上系统的移动网络开关

Posted jhcelue

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android5.0以上系统的移动网络开关相关的知识,希望对你有一定的参考价值。

笔者近期遇到一个非常有意思的bug,贴出来和大家分享下。
那是一个温暖的早晨,阳光晒得人非常舒服。一封bug邮件像一片叶子飘到我的邮箱。

一番交流。笔者确认负责的Widget开关在android5.0以上系统没有作用。相信非常多做过移动网络开关的朋友都知道。传统的方法是在ConnectivityManager中通过反射两个方法setMobileDataEnabled和getMobileDataEnabled来控制移动网络开和关的。

    /**
     * Gets the value of the setting for enabling Mobile data.
     *
     * @return Whether mobile data is enabled.
     * @hide
     */
    public boolean getMobileDataEnabled() {
        try {
            return mService.getMobileDataEnabled();
        } catch (RemoteException e) {
            return true;
        }
    }

    /**
     * Sets the persisted value for enabling/disabling Mobile data.
     *
     * @param enabled Whether the mobile data connection should be
     *            used or not.
     * @hide
     */
    public void setMobileDataEnabled(boolean enabled) {
        try {
            mService.setMobileDataEnabled(enabled);
        } catch (RemoteException e) {
        }
    }

可是打开5.0以上的源代码,这两个方法已经不存在了。
推荐一个不错的在线看源代码的站点。在线源代码网址

此时老大的提醒帮了我。我打开5.0以上代码的TelephonyMananger类尝试通过反射获取setDataEnabled和getDataEnabled类完毕操作。
源代码

/** @hide */
    @SystemApi
    public void setDataEnabled(boolean enable) {
        try {
            getITelephony().setDataEnabled(enable);
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#setDataEnabled", e);
        }
    }

    /** @hide */
    @SystemApi
    public boolean getDataEnabled() {
        try {
            return getITelephony().getDataEnabled();
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#getDataEnabled", e);
        }
        return false;
    }

我的反射方法:

public void setMobileDataState(Context cxt, boolean mobileDataEnabled) {
        TelephonyManager telephonyService = (TelephonyManager) cxt.getSystemService(Context.TELEPHONY_SERVICE);
    try {
        Method setMobileDataEnabledMethod = telephonyService.getClass().getDeclaredMethod("setDataEnabled", boolean.class);
        if (null != setMobileDataEnabledMethod)
        {
            setMobileDataEnabledMethod.invoke(telephonyService, mobileDataEnabled);
        }
    }
    catch (Exception e) {
        LogHelper.v(TAG, "Error setting" + ((InvocationTargetException)e).getTargetException() + telephonyService);
    }
}

public boolean getMobileDataState(Context cxt) {
        TelephonyManager telephonyService = (TelephonyManager) cxt.getSystemService(Context.TELEPHONY_SERVICE);
    try {
        Method getMobileDataEnabledMethod = telephonyService.getClass().getDeclaredMethod("getDataEnabled");
        if (null != getMobileDataEnabledMethod)
        {
            boolean mobileDataEnabled = (Boolean) getMobileDataEnabledMethod.invoke(telephonyService);
            return mobileDataEnabled;
        }
    }
    catch (Exception e) {
        LogHelper.v(TAG, "Error getting" + ((InvocationTargetException)e).getTargetException() + telephonyService);
    }

    return false;
}

可是报了InvocationTargetException错误。

通过:

((InvocationTargetException)e).getTargetException()

方法得知是运行反射运行时发生例如以下错误:

Error settingjava.lang.SecurityException: Neither user 10240 nor current process has android.permission.MODIFY_PHONE_STATE.android.telephony.TelephonyManager

这个时候老大提醒我把APP移动到system/app下试试。


几番尝试。仍是相同的结果。

这个时候一个我无意的操作,将APP移动到system/priv-app,居然成功了。在这个文件夹下,开关又能够又一次工作了。

当然,我们的应用不可能装在这个文件夹下,仅仅能採取折中的方案。但整个过程还是非常开心的,这个bug算是我第一次发现了不同Android版本号之间源代码的差异,感觉非常有意思。希望对大家有所启示。





以上是关于Android5.0以上系统的移动网络开关的主要内容,如果未能解决你的问题,请参考以下文章

Android5.0以上实现对手机屏幕录制并将视频实时保存到本地(亦可实时传输)

《完美解决系列》Android5.0以上 Implicit intents with startService are not safe

android5.0以上对于APP_SWITCH和HOME键的处理

Android5.0以上app进程保活的正确姿势

Android5.0以上的项目都会有的按钮点击特效--水波纹

导航栏后面的内容