androidsleepandroid-wake-lockphone-state-listenersignal-strength

Android, getting strength signal (PhoneStateListener) while device in sleep mode


I have problem and after some search I have not found any positive solutions. After research I have idea that there is not implementation for my problem but this question may be is my last chance.

What do I need to get?

There is application that gets information about mobile network strength signal. I do it by PhoneStateListener. Of course it works great but when my device goes to sleep mode, listener does not work:

https://code.google.com/p/android/issues/detail?id=10931 https://code.google.com/p/android/issues/detail?id=7592

WakeLock solves problem only in case, if device switch off by timeout. In case when I press hard power button, my device gets sleep mode as well. We can not override power button action.

My goal is get strength signal always when my device is enabled. It does not matter what mode is. All time it should collecting data.

Question:

Are there any ideas? How to achieve that? Are there ways to do this or may be there are some hacks? All solves are welcome. If you had some useful experience, please share this.

Thanks to all for help!!! I hope, this topic will get complete information about this problem.


Solution

  • Alarm manager is the way to go - the tricky part is to keep the phone awake after the alarm manager receiver returns. So

    If the receiver ANRs on you, you have to try the WakefulIntentService pattern. In either case you might use this :

    This proved the most difficult part actually :

    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;
        }
    }
    

    where :

    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;
        }
    }
    

    This is working code (but not the pinnacle of elegance admittedly - comments/corrections welcome). Do not forget to register your services in the manifest and acquire permissions.
    EDIT 2013.07.23 : I did not use the onReceive - if you use it it will ANR - this is working code if you use a WakefulIntentService in onReceive and in there you call SignalListenerService.