Android, obteniendo la señal de intensidad (PhoneStateListener) mientras el dispositivo está en modo de suspensión
Tengo problema y después de alguna búsqueda no he encontrado ninguna solución positiva. Después de la investigación tengo la idea de que no hay aplicación para mi problema, pero esta pregunta puede ser es mi última oportunidad.
¿Qué necesito obtener?
- NullPointerExecption al llamar a un PhoneStateListener en un servicio
- Android, TelephonyManager, las alegrías de PhoneStateListener y los números entrantes
- La aplicación de Android que supervisa las llamadas entrantes mantiene el teléfono despierto
- Android: obtenga CellID y RSS para la estación base y las celdas Neigboring
- Cómo detectar el estado contestado o rechazado en la llamada saliente
Hay aplicación que obtiene información sobre la señal de intensidad de red móvil. Lo hago por PhoneStateListener
. Por supuesto, funciona muy bien, pero cuando mi dispositivo pasa al modo de suspensión, el oyente no funciona:
Https://code.google.com/p/android/issues/detail?id=10931 https://code.google.com/p/android/issues/detail?id=7592
WakeLock
soluciona el problema sólo en caso de que el dispositivo se apague por tiempo de espera. En caso de que cuando presione el botón de encendido, el dispositivo obtendrá el modo de suspensión también. No podemos anular la acción del botón de encendido.
Mi meta es conseguir la señal de la fuerza siempre cuando mi dispositivo está permitido. No importa cuál sea el modo. Todo el tiempo debe recolectar datos.
Pregunta:
¿Hay alguna idea? ¿Cómo lograrlo? ¿Hay maneras de hacer esto o puede ser que hay algunos hacks? Todas las soluciones son bienvenidas. Si usted tuvo alguna experiencia útil, por favor comparta esto.
Gracias a todos por la ayuda! Espero que este tema obtenga información completa sobre este problema.
- Ya que Android 6.0 escuchando los cambios de PhoneStateListener.LISTEN_DATA_CONNECTION_STATE parece que ya no necesita permiso de READ_PHONE_STATE
- Incapaz de crear servicio java.lang.NullPointerException
- PhoneStateListener en el subproceso de fondo
- Mover la pantalla de llamadas entrantes predeterminadas a fondo en TelephonyManager.CALL_STATE_RINGING en Android
- Añadir PhoneStateListener
- ¿PhoneStateListener funciona en Phonegap Plugin?
- Recuperar el número de teléfono de la llamada entrante en Android
Administrador de alarmas es el camino a seguir – la parte difícil es mantener el teléfono despierto después de que el receptor del administrador de alarmas regrese. Asi que
-
Configurar una alarma (observe que también debe registrar un receptor "On Boot completed" para configurar la alarma después de un reinicio – sus alarmas no sobreviven a un reinicio):
Intent monitoringIntent = new Intent(context, YourReceiver.class); monitoringIntent.setAction("your action"); PendingIntent pi = PendingIntent.getBroadcast(context, NOT_USED, monitoringIntent, PendingIntent.FLAG_UPDATE_CURRENT); AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); // here is the alarm set up am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + INITIAL_DELAY, INTERVAL_BETWEEN_ALARMS, pi);
-
Recibirlo – el receptor tiene un WakeLock en su
onReceive()
que nunca falla:public abstract class YourReceiver extends BroadcastReceiver { @Override final public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if ("your action".equals(action)) { // monitoring - got broadcast from ALARM try { d("SS : " + new Signal().getSignalStrength(context)); } catch (InterruptedException e) { e.printStackTrace(); } // Actu8ally the lines above will ANR // I did it with WakefulIntentService : // WakefulIntentService.sendWakefulWork( // context, YourWakefulService.class); // Will be posting it asap } else { w("Received bogus intent : " + intent); return; } } }
Si tienes suerte (yourRetrieveSignal () es lo suficientemente rápido) esto funcionará, de lo contrario necesitarás un patrón (Wakeful) IntentService en tu receptor.
El WakefulIntentService se encargará del bloqueo de la vigilia (si desea evitar una dependencia eche un vistazo aquí ) – EDIT: tenga en cuenta que no puede definir los oyentes en un servicio de intención – vea aquí .
Si el receptor ANRs en ti, tienes que probar el patrón WakefulIntentService. En cualquier caso, puede utilizar esto :
Esto demostró ser la parte más difícil en realidad:
class Signal { static volatile CountDownLatch latch; //volatile is an overkill quite probably static int asu; private final static String TAG = Signal.class.getName(); int getSignalStrength(Context ctx) throws InterruptedException { Intent i = new Intent(TAG + ".SIGNAL_ACTION", Uri.EMPTY, ctx, SignalListenerService.class); latch = new CountDownLatch(1); asu = -1; ctx.startService(i); Log.d(TAG, "I wait"); latch.await(); ctx.stopService(i); return asu; } }
dónde :
public class SignalListenerService extends Service { private TelephonyManager Tel; private SignalListener listener; private final static String TAG = SignalListenerService.class.getName(); private static class SignalListener extends PhoneStateListener { private volatile CountDownLatch latch; private SignalListener(CountDownLatch la) { Log.w(this.getClass().getName(), "CSTOR"); this.latch = la; } @Override public void onSignalStrengthChanged(int asu) { Signal.asu = asu; latch.countDown(); } } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.w(TAG, "Received : " + intent.getAction()); Tel = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); listener = new SignalListener(Signal.latch); @SuppressWarnings("deprecation") final int listenSs = PhoneStateListener.LISTEN_SIGNAL_STRENGTH; Tel.listen(listener, listenSs); return START_STICKY; } @Override public void onDestroy() { Log.w(TAG, "onDestroy"); Tel.listen(listener, PhoneStateListener.LISTEN_NONE); super.onDestroy(); } @Override public IBinder onBind(Intent intent) { return null; } }
Este es el código de trabajo (pero no el pináculo de la elegancia de hecho – comentarios / correcciones bienvenido). No olvide registrar sus servicios en el manifiesto y adquirir permisos.
EDITAR 2013.07.23: No onReceive
el onReceive
– si lo usas será ANR – este es el código de trabajo si usas WakefulIntentService en onReceive
y ahí llamas SignalListenerService
.
Desde mi comprensión de PhoneStateListener no se puede hacer esto mientras la CPU de la aplicación está en modo de suspensión. Puede mantener el dispositivo despierto, lo que arruinaría la vida de la batería. Alternativamente, puede utilizar una alarma (consulte AlarmManager ) para activar el dispositivo en intervalos, de modo que pueda recopilar los datos (impacta la duración de la batería).
Algunas muestras de AlarmManager se pueden encontrar aquí
El ejemplo de polling de la ubicación de CommonsWare es realmente bueno acerca de despertar el teléfono y ponerlo de nuevo a dormir. Creo que podría ayudar a echar un vistazo: https://github.com/commonsguy/cwac-locpoll
Una de las soluciones posibles del problema android 10931 es enviar la intención android.intent.action.SCREEN_ON
al proceso 'phone' después de que la pantalla se apagara.
-
Crear y registrar
BroadcastReceiver
para escuchar las notificaciones cuando la pantalla se apagastart(Context context) { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); context.registerReceiver(mScreenReceiver, filter); } final BroadcastReceiver mScreenReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { Log.v(LOGTAG, "Screen is off. Running workaround"); new Thread(mReportScreenIsOnRunnable).start(); } } };
-
Envíe la intención
SCREEN_ON
al proceso del teléfono solamente.public final Runnable mReportScreenIsOnRunnable = new Runnable() { @Override public void run() { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } try { Runtime.getRuntime().exec(new String[] { "su", "-c", "am broadcast -a android.intent.action.SCREEN_ON com.android.phone" }); } catch (IOException e) { e.printStackTrace(); } } };
Después de recibir este intento el proceso del teléfono reanudaría el envío de las actualizaciones de la localización de la célula.
Se requieren privilegios raíz.
Esta solución es un poco hacky, peligroso y no funciona en todos los teléfonos. Puede conducir a un mayor consumo de energía, pero no mucho más que si mantiene la pantalla encendida.