4

Following this guide https://developer.android.com/training/monitoring-device-state/battery-monitoring.html

I made a receiver that should log battery info to a file every time charger is plugged or unplugged. The activity reads the content of this file and displays it on screen. This is supposed to work always regardless of the app running, but it doesn't. It only registers if the app is open/in memory, when I clear the memory or reboot it stops working.

Manifest:

  <receiver android:name=".Receiver">
        <intent-filter>
            <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
            <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
        </intent-filter>
    </receiver>

Receiver:

public class Receiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
      Intent chargingIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
      final int status = chargingIntent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
      int level = chargingIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
      int plugged = chargingIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
      Battery battery = new Battery();
      battery.setLevel(level);
      battery.setDate(new Date());
      battery.setPlugged(plugged);
      battery.setStatus(status);
      Logger.log(JSON.toJSONString(battery));
    }
}

Logger

public class Logger {

public static void log(String text)
{
    File logFile = new File(Environment.getExternalStorageDirectory().getPath()+"/batterylog.txt");
    Log.d("files"," logfile "+logFile+": "+logFile.exists());

    if (!logFile.exists())
    {
        try
        {
            logFile.createNewFile();
            Log.d("files","new logfile created"+logFile);
        }
        catch (IOException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    try
    {
        //BufferedWriter for performance, true to set append to file flag
        BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
        buf.append(text).append("\r\n");
        buf.flush();
        buf.close();
    }
    catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
}

This is what it looks like after unplugging while app is open:

enter image description here

When it's not it's just empty.

Asalas77
  • 612
  • 4
  • 15
  • 26
  • You need to register a service that listens for this broadcast in the background. – ditn Jan 20 '17 at 15:16
  • @ditn I was following this guide: https://developer.android.com/training/monitoring-device-state/battery-monitoring.html and it says `BroadcastReceiver` should trigger even if the app if closed. That's not the case? – Asalas77 Jan 20 '17 at 15:19
  • `onReceive` is certainly getting called in above code, when app is running or not. you can put a simple `Log.i` statement inside your `onReceive`to confirm the same. I guess the issue is in your other piece of code. Can you tell what is `Battery` class? it is certainly not an Android-framework provided class. Also, there is no Logger.log API in Logger class the way you mentioned in your code. Are these your custom classes? Also, how are you testing this code? I mean how you KNOW that above is not working? – AADProgramming Jan 21 '17 at 17:04
  • @AADTechnical I used a custom logger that writes to a file instead of console. That is because my receiver is triggered by unplugging the cable so I don't see the logs in Android Studio. The logs are not being written, my app displays the contents of this file in activity. Battery is just a a model class with 4 fields. – Asalas77 Jan 24 '17 at 13:27
  • @AADTechnical added logger and a screenshhot to the post – Asalas77 Jan 24 '17 at 13:33
  • 1
    @Asalas77 I have noticed that this problem is there with few of the devices. I faced the same problem when I tried to run my app on "Lenovo A 600PLUS" it didn't work, the same app is running fine in other devices. – Rajeev Mar 17 '17 at 05:57
  • did u got solution? – Jithish P N Oct 23 '17 at 10:24
  • 1
    @JithishPN no, I figured it was a software limitation of my OS or device and shelved this app for now. I'm running MIUI 8, which is a quite heavily modified Android 7 and a lot of things work differently on stock Android. – Asalas77 Oct 26 '17 at 12:43
  • Also note that, if you are targeting API 26 or higher and are running on Android 8 (Oreo) or higher, then this will no longer work: Android 8 has restricted the ability of manifest-declared receivers to receive implicit broadcasts (which do not specify a component) to a few intents, and the ones you are using are not in the exception list (see https://developer.android.com/guide/components/broadcasts#manifest-declared-receivers and https://commonsware.com/blog/2017/04/11/android-o-implicit-broadcast-ban.html). Therefore, your solution may no longer work on newer versions of Android. – user149408 Jun 24 '18 at 18:28
  • Forgot to mention, apparently some Android distributions do not wake apps for implicit broadcasts even prior to version 8 and for apps targeting API 25 or lower. If the app is running, the broadcast will be delivered, else the app will miss it. From my experience, this seems to be the case on LineageOS 14.1. – user149408 Jun 24 '18 at 19:02

2 Answers2

2

Try to set android:enabled="true" to your receiver

Like this

 <receiver android:name=".Receiver"
    android:enabled="true">
        <intent-filter>
            <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
            <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
        </intent-filter>
    </receiver>

Update

I just implemented it in my app your's way and it worked. But I did it with right click->new->other->broadcast receiver

After inserting intent-filter I got code like this

    <receiver
        android:name=".MyReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
            <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
        </intent-filter>
    </receiver>

And it actually calling onReceive method

Ekalips
  • 1,473
  • 11
  • 20
  • added `exported` attribute, but still no change. Doesn't seem to be related according to the documentation too – Asalas77 Jan 20 '17 at 15:56
  • Try to add again with Android Studio helper (right click on files and so on) –  Ekalips Jan 20 '17 at 15:58
  • Did that, the only noticable difference is an empty contrucor in receiver, but still no change. Doesn't trigger after reboot or closing app from manager – Asalas77 Jan 20 '17 at 16:16
0

Did you try using wake-locks? Generally app will wake up on the receive of broascast butif it doesnot (happens in few devices), then try using wake-locks which will forcefully wake up the device.

How to use wake-locks :

//Register for wake-locks

if (mWakeLock == null) {
        PowerManager pm = (PowerManager)yourcontext.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, yourcontext);
        mWakeLock.setReferenceCounted(false);

}

//Apply wake-lock using acquire

mWakeLock.acquire();