Android:如何获取所有可用网络运营商的GSM信号强度

45

我正在开发一个小应用程序,用于检查我所在区域各个网络运营商的信号强度。目前我的运营商信号相当不稳定,我想了解其他GSM运营商的信号强度。

到目前为止,我一直使用TelephonyManager和一个PhoneStateListener,通过onSignalStrengthsChanged回调来获取当前网络运营商的GSM信号强度,但是似乎这个类只能提供与我的SIM卡连接的网络的信号强度信息。

我对所有可用运营商的GSM信号强度测量很感兴趣。在网上搜索得到了使用Android内部类的模糊提示,但我还没有找到任何好的示例。

非常感谢任何能帮助我获得所有可用网络运营商及其信号强度列表的答案。


简单易懂的教程 - mihirjoshi
你好,你有得到这个问题的答案吗?如果有,请给一些示例。我需要和你一样的要求。 - reegan29
我知道这是一个旧帖子,但你完成了你的应用程序吗?它可以在哪里下载? - Philipp
你好@Schwartz,我正在寻找相同的需求。你找到解决方案了吗?如果你能提供任何付费/免费的API,那就太好了。 - Praveen Mishra
4个回答

24
也许以下的引用和链接可以帮助你编写自己的解决方案:
1.- 要获取可用网络提供商列表(全文引用自如何获取可用网络提供商列表?):
“由于Android是开源的,我查看了源代码,最终找到了一个名为INetworkQueryService的东西。我猜你可以像android设置实现一样与这个服务交互。通过NetworkSettings.java提供一些指导:”
  • 在onCreate中启动NetworkQueryService并进行绑定。
  • loadNetworksList()方法告诉服务查询网络运营商。
  • 对INetworkQueryServiceCallback进行评估,如果引发了“EVENT_NETWORK_SCAN_COMPLETED”事件,则会调用networksListLoaded方法以遍历可用网络。
2.- 即使快速阅读NetworkSetting.javaINetworkQueryService interface,也能给我们一个实现你目标的想法。
  • 在声明中连接服务。
/**
 * Service connection code for the NetworkQueryService.
 * Handles the work of binding to a local object so that we can make
 * the appropriate service calls.
 */

/** Local service interface */
private INetworkQueryService mNetworkQueryService = null;

/** Service connection */
private final ServiceConnection mNetworkQueryServiceConnection = new ServiceConnection() {

    /** Handle the task of binding the local object to the service */
    public void onServiceConnected(ComponentName className, IBinder service) {
        if (DBG) log("connection created, binding local service.");
        mNetworkQueryService = ((NetworkQueryService.LocalBinder) service).getService();
        // as soon as it is bound, run a query.
        loadNetworksList();
    }

    /** Handle the task of cleaning up the local binding */
    public void onServiceDisconnected(ComponentName className) {
        if (DBG) log("connection disconnected, cleaning local binding.");
        mNetworkQueryService = null;
    }
};
onCreate启动NetworkQueryService并将其绑定。
Intent intent = new Intent(this, NetworkQueryService.class);
...
startService (intent);
bindService (new Intent(this, NetworkQueryService.class), mNetworkQueryServiceConnection,
                        Context.BIND_AUTO_CREATE);
  • loadNetworksList() 告诉服务查询网络运营商。
private void loadNetworksList() {
...    
// delegate query request to the service.
try {
    mNetworkQueryService.startNetworkQuery(mCallback);
} catch (RemoteException e) {
}

displayEmptyNetworkList(false); 
}
  • 评估 INetworkQueryServiceCallback:
/**
 * This implementation of INetworkQueryServiceCallback is used to receive
 * callback notifications from the network query service.
 */
private final INetworkQueryServiceCallback mCallback = new INetworkQueryServiceCallback.Stub() {

    /** place the message on the looper queue upon query completion. */
    public void onQueryComplete(List<OperatorInfo> networkInfoArray, int status) {
        if (DBG) log("notifying message loop of query completion.");
        Message msg = mHandler.obtainMessage(EVENT_NETWORK_SCAN_COMPLETED,
                status, 0, networkInfoArray);
        msg.sendToTarget();
    }
};
如果事件“EVENT_NETWORK_SCAN_COMPLETED”被触发,将调用networksListLoaded来迭代可用的网络。
  • The program uses a recursive algorithm to traverse the directory structure and find all the files that match the specified extension.
该程序使用递归算法遍历目录结构并查找与指定扩展名匹配的所有文件。
  • The user can customize the font size and color of the text in the settings menu.
用户可以在设置菜单中自定义文本的字体大小和颜色。
  • To add a new item to the list, click on the "Add Item" button and fill out the required fields in the form.
要向列表中添加新项目,请单击“添加项目”按钮并填写表格中的必填字段。
  • The application supports multiple languages ​​including English, French, and Spanish.
该应用程序支持多种语言,包括英语、法语和西班牙语。
private void networksListLoaded(List<OperatorInfo> result, int status) {
    ...

    if (status != NetworkQueryService.QUERY_OK) {
        ...
        displayNetworkQueryFailed(status);
        displayEmptyNetworkList(true);
    } else {
        if (result != null){
            displayEmptyNetworkList(false);
            ...
        } else {
            displayEmptyNetworkList(true);
        }
    }
}
我希望这有所帮助。我觉得这是一个有趣的挑战,也许下次我有空会试试。祝你好运!

你如何导入像 INetworkQueryService 这样的项目?我找不到 Eclipse 可以识别的路径。 - Neil Townsend
抱歉今天无法尝试,但如果import com.android.phone.INetworkQueryService无法工作,您可以复制代码并使用相同的原则创建自己的解决方案(基本上,这就是我在答案中尝试表达的意思)。 - Alejandro Colorado
这正是我所做的:我从头开始创建了一个Activity,并使用了您建议的代码。然而,很多被引用的类,例如INetworkQueryServiceNetworkQueryService都无法被识别,Eclipse找不到它们的导入,而明显的猜测(例如import com.android.phone.INetworkQueryService)会导致The import com.android.phone cannot be resolved。您有什么建议? - Neil Townsend
1
我已经尝试了一个多月,但仍不知道如何将这个假设设置为正确答案(或获得175分)。有人尝试过吗?成功了吗?我无法获取NetworkQueryService的实例,因为它是一个内部类。要做到这一点,我应该使用包含该类实例的对象,但我不知道在哪里找到它或是否真的可以找到。请帮我解决这个问题。 - williamlopes
1
这可能允许您获取OperatorInfo结构的列表,但是OperatorInfo仅包含长名称、短名称、数字ID以及您是否被允许/注册在该网络中。它不包含信号强度或网络类型(GSM / 3G / 4G)! - ge0rg
显示剩余2条评论

2
private final PhoneStateListener phoneStateListener = new PhoneStateListener() {
    @Override
    public void onCallForwardingIndicatorChanged(boolean cfi) {

        super.onCallForwardingIndicatorChanged(cfi);
    }

    @Override
    public void onCallStateChanged(int state, String incomingNumber) {
        //checkInternetConnection();
        String callState = "UNKNOWN";
        switch (state) {
        case TelephonyManager.CALL_STATE_IDLE:
            callState = "IDLE";
            break;
        case TelephonyManager.CALL_STATE_RINGING:
            callState = "Ringing (" + incomingNumber + ")";
            break;
        case TelephonyManager.CALL_STATE_OFFHOOK:
            callState = "Offhook";
            break;
        }

        Log.i("Phone Stats", "onCallStateChanged " + callState);

        super.onCallStateChanged(state, incomingNumber);
    }

    @Override
    public void onCellLocationChanged(CellLocation location) {
        String cellLocationString = location.toString();

        super.onCellLocationChanged(location);



    }

    @Override
    public void onDataActivity(int direction) {
        String directionString = "none";
        switch (direction) {
        case TelephonyManager.DATA_ACTIVITY_IN:
            directionString = "IN";
            break;
        case TelephonyManager.DATA_ACTIVITY_OUT:
            directionString = "OUT";
            break;
        case TelephonyManager.DATA_ACTIVITY_INOUT:
            directionString = "INOUT";
            break;
        case TelephonyManager.DATA_ACTIVITY_NONE:
            directionString = "NONE";
            break;
        default:
            directionString = "UNKNOWN: " + direction;
            break;
        }

        Log.i("Phone Stats", "onDataActivity " + directionString);

        super.onDataActivity(direction);
    }

    @Override
    public void onDataConnectionStateChanged(int state,int networktype) {
        String connectionState = "Unknown";

        switch (state ) {

        case TelephonyManager.DATA_CONNECTED :
            connectionState = "Connected";
            break;
        case TelephonyManager.DATA_CONNECTING:
            connectionState = "Connecting";
            break;
        case TelephonyManager.DATA_DISCONNECTED:
            connectionState = "Disconnected";
            break;
        case TelephonyManager.DATA_SUSPENDED:
            connectionState = "Suspended";
            break;
        default:
            connectionState = "Unknown: " + state;
            break;
        }

        super.onDataConnectionStateChanged(state);


        Log.i("Phone Stats", "onDataConnectionStateChanged "
                + connectionState);


    }

    @Override
    public void onMessageWaitingIndicatorChanged(boolean mwi) {

        super.onMessageWaitingIndicatorChanged(mwi);
    }

    @Override
    public void onServiceStateChanged(ServiceState serviceState) {
        String serviceStateString = "UNKNOWN";
        switch (serviceState.getState()) {
        case ServiceState.STATE_IN_SERVICE:
            serviceStateString = "IN SERVICE";
            break;
        case ServiceState.STATE_EMERGENCY_ONLY:
            serviceStateString = "EMERGENCY ONLY";
            break;
        case ServiceState.STATE_OUT_OF_SERVICE:
            serviceStateString = "OUT OF SERVICE";
            break;
        case ServiceState.STATE_POWER_OFF:
            serviceStateString = "POWER OFF";
            break;

        default:
            serviceStateString = "UNKNOWN";
            break;
        }

        Log.i("Phone Stats", "onServiceStateChanged " + serviceStateString);

        super.onServiceStateChanged(serviceState);
    }

    @Override
    public void onSignalStrengthChanged(int asu) {

        Log.i("Phone Stats", "onSignalStrengthChanged " + asu);
        setSignalLevel( asu);
        super.onSignalStrengthChanged(asu);
    }
    private void setSignalLevel(int level) {
        int sLevel = (int) ((level / 31.0) * 100);


        Log.i("signalLevel ", "" + sLevel);
    }

};

8
谢谢回复,但是这段代码只能给出有关所订阅网络的信息,我还想了解该地区其他运营商的信号强度。 - The Schwartz
1
当你搜索网络时,运营商会显示在列表中,你想知道所有显示的运营商的网络强度,对吗? - Sandeep
1
没错,我想看到我当前所在地所有可能的网络运营商及其信号强度列表。 - The Schwartz

1
由于我没有50个声望点,所以这是我对该主题搜索的结果:
Alejandro Colorado的解决方案似乎是好的。但问题在于用于实现它的类是保留给Android系统应用程序的,即使用与系统相同签名密钥的应用程序。
怎么可能呢?我找到了两种方法来实现这一点。
第一种方法是在任何制造商公司申请工作,并签署他们的NDA,但嘿,这不是一个真正好的解决方案。特别是因为使用此密钥实现并签署的应用程序只能在公司设备上运行...
第二种方法更加有趣,但我警告你,这不会很容易,那就是制作自己的ROM。您将需要创建自己的应用程序,将其插入ROM的/system/app/目录中,并重新编译ROM以使用新系统刷写设备。但还有一个问题我还没有回答,那就是未被识别的ROM签名问题。我认为避免这个问题的最佳方法是在您将要使用的恢复中添加ROM签名密钥。
这就是我目前的情况,也许你会发现这些研究有用,希望如此!如果我为你们找到更多信息,我会稍后回来。再见。

0
创建一个PhoneStateListener并处理onSignalStrengthChanged回调。当您的应用程序初始化时,它应该向您发送初始通知。这是在1.x中。在2.x中,有一个关于此问题的开放问题

1
感谢您的快速回复。我已经按照上述说明尝试过了,但它只给出了当前网络运营商信号的信号强度。我对所有可用运营商及其当前信号强度的完整列表感兴趣。 - The Schwartz
我从未尝试过这些,我会搜索一下,如果找到任何答案,我会在这里发布。 - Krishnakant Dalal
“我对所有可用运营商及其当前信号强度的完整列表感兴趣。”的意思是什么? - Sandeep
完整的列表意味着手机当前位置所有可用的网络运营商。 - The Schwartz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接