ti-enxame.com

Como acesso dados móveis no Android

Contagem rápida antes que alguém me diga para comprar um aplicativo. =)

Acabei de receber um EVO e ele mastiga rapidamente a bateria. Eu baixei o JuiceDefender para gerenciar minha conexão de dados móveis. Isso parece ter funcionado razoavelmente bem. No entanto, as configurações são muito restritas (mesmo nas versões pagas).

A partir de agora, estou tentando desenvolver um aplicativo de economia de bateria muito mais personalizável. A principal coisa que estou tentando fazer primeiro é ativar/desativar a conexão de dados móveis à vontade. 

O problema é que não consigo encontrar nenhum trecho de código ou artigos sobre como fazer isso. A única coisa que encontrei é a seguinte. Eu não sei o quão preciso isso é, mas isso foi tudo o que eu poderia juntar navegando developer.Android.com

ConnectivityManager cm = (ConnectivityManager) this.getSystemService(CONNECTIVITY_SERVICE);
cm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "Android.net.conn.CONNECTIVITY_CHANGE");

State state = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState();
textView.setText(state.name());

Se alguém puder me indicar algo que possa ajudar, seria muito apreciado.

ATUALIZAR

Parece que o HTC Evo no Sprint não usa configurações de APN. Eu testei isso baixando APNDroid e vendo que não funciona. Em seguida, fiz um aplicativo rápido para despejar todas as entradas do APN na tela. Isso rendeu um resultado e foi por mms.

Olhando para as informações do telefone quando o JuiceDefender está em execução, descobri que a rede GSRP está sendo ativada e desativada. Isso me faz acreditar que é possível fazer isso através de código, mesmo que todas as páginas que eu encontre perguntando sobre esse mesmo problema afirmem que isso não pode ser feito. O kicker é todos eles dizem para fazer isso como APNDroid. Por favor, alguém me dê algumas dicas. 

Obrigado!

44
TyCobb

A desativação do Dataconnection e a ativação do APIS estão ocultos no SDK e não expostos ao usuário. Isso pode ser obtido acessando a interface do ITelephony usando a técnica de reflexão Java.

aqui está:

    Method dataConnSwitchmethod;
    Class telephonyManagerClass;
    Object ITelephonyStub;
    Class ITelephonyClass;

    TelephonyManager telephonyManager = (TelephonyManager) context
            .getSystemService(Context.TELEPHONY_SERVICE);

    if(telephonyManager.getDataState() == TelephonyManager.DATA_CONNECTED){
        isEnabled = true;
    }else{
        isEnabled = false;  
    }   

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

    if (isEnabled) {
        dataConnSwitchmethod = ITelephonyClass
                .getDeclaredMethod("disableDataConnectivity");
    } else {
        dataConnSwitchmethod = ITelephonyClass
                .getDeclaredMethod("enableDataConnectivity");   
    }
    dataConnSwitchmethod.setAccessible(true);
    dataConnSwitchmethod.invoke(ITelephonyStub);
38
Indra

A partir de 'Gingerbread' você pode usar o método IConnectivityManager.setMobileDataEnabled (). Está oculto na API, mas pode ser acessado com reflection. http: //grepcode.com/file/repository.grepcode.com/Java/ext/com.google.Android/android/2.2_r1.1/Android/net/ConnectivityManager.Java#376

Com esse método, você pode alterar a configuração do sistema: 'Configurações -> Sem fio e rede -> Configurações de rede móvel -> Dados ativados'

Exemplo de código:

private void setMobileDataEnabled(Context context, boolean enabled) {
    final ConnectivityManager conman = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    final Class conmanClass = Class.forName(conman.getClass().getName());
    final Field iConnectivityManagerField = conmanClass.getDeclaredField("mService");
    iConnectivityManagerField.setAccessible(true);
    final Object iConnectivityManager = iConnectivityManagerField.get(conman);
    final Class iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName());
    final Method setMobileDataEnabledMethod = iConnectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
    setMobileDataEnabledMethod.setAccessible(true);

    setMobileDataEnabledMethod.invoke(iConnectivityManager, enabled);
}

Além disso, você precisa da permissão CHANGE_NETWORK_STATE.

<uses-permission Android:name="Android.permission.CHANGE_NETWORK_STATE"/>

Escusado será dizer que esta abordagem pode não funcionar em futuras versões do Android. Mas eu acho que aplicativos como '3G watchdog', 'APNdroid' ou 'DataLock' funcionam dessa maneira.


UPDATE:
O método setMobileDataEnabled não está mais disponível no Lollipop

72
Vladimir Sorokin

Mudar a conectividade da rede de dados móveis, alterando o nome da APN, não funciona mais desde o Gingerbread. E, embora o código de reflexão seja provavelmente o jeito certo de fazer o truque, ele não funcionará, porque o aplicativo precisa da permissão Android.permission.MODIFY_PHONE_STATE como explicado por Alex P. Caso contrário, você terá esta exceção desagradável:

03-18 21:54:55.074: WARN/System.err(1851): Java.lang.reflect.InvocationTargetException
(...)
03-18 21:54:55.263: WARN/System.err(1851): Caused by: Java.lang.SecurityException: Neither user 10037 nor current process has Android.permission.MODIFY_PHONE_STATE.
(...)
03-18 21:54:55.303: WARN/System.err(1851):     at com.Android.internal.telephony.ITelephony$Stub$Proxy.disableDataConnectivity(ITelephony.Java:888)

Infelizmente, você não pode definir essa permissão porque ela é uma permissão de nível 3 não permitida para aplicativos:

03-18 21:48:39.334: WARN/PackageManager(75): Not granting permission Android.permission.MODIFY_PHONE_STATE to package XXX (protectionLevel=3 flags=0x8be46)

Eu não suponho que alguém tenha uma maneira de substituir a supressão de concessão de permissão diferente de usar o próprio firmware.

4
Z80

Observe que "Android.permission.MODIFY_PHONE_STATE" não é mais compatível com Android 2.3 e superior.

porque 2.3 versão do Android não hava Android.permission.MODIFY_PHONE_STATE? e qual é a solução para isso?

3
Muzikant

para adicionar um botão de alternância, você pode usar este código, além da resposta de Vladimir:

TelephonyManager telephonyManager = (TelephonyManager) context
                .getSystemService(Context.TELEPHONY_SERVICE);
switch (telephonyManager.getDataState()) {
        case TelephonyManager.DATA_CONNECTED:
            setMobileDataEnabledMethod.invoke(iConnectivityManager, false);
            break;
        case TelephonyManager.DATA_DISCONNECTED:
            setMobileDataEnabledMethod.invoke(iConnectivityManager, true);
            break;
        }

Esta solução alternativa de reflexão ainda está funcionando para mim no Android 4.0.4

3
greg121

Eu acho que existem dois tipos principais de conexão de dados móveis em um dispositivo Android: WiFi e 3G/HSDPA/etc.

E afaik você deve ser capaz de desativar o WiFi programaticamente, mas eu acho que as conexões 3G/HSDPA/etc só podem ser desativadas alterando o nome do APN. A razão pela qual estou dizendo isso é porque o aplicativo popular APNDroid faz desse jeito.

3
Telmo Marques

@Mariux: Você provavelmente esqueceu de adicionar <uses-permission Android:name="Android.permission.MODIFY_PHONE_STATE" /> ao AndroidManifest.xml

0
Alex P.
    final ConnectivityManager conman = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    final Class conmanClass = Class.forName(conman.getClass().getName());
    final Field connectivityManagerField = conmanClass.getDeclaredField("mService");
    connectivityManagerField.setAccessible(true);
    final Object connectivityManager = connectivityManagerField.get(conman);
    final Class connectivityManagerClass = Class.forName(connectivityManager.getClass().getName());
    final Method setMobileDataEnabledMethod = connectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
    setMobileDataEnabledMethod.setAccessible(true);

    setMobileDataEnabledMethod.invoke(connectivityManager, enabled); // pass true or false
0
Krishna Patel