Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NotificationListenerService and Doze mode and App Standby

I have an app that listens for phone notifications and sends a message to an Android Wear watch via the MessageApi. Everything works good except for some devices with Android 6, especially Huawei Mate 8 (looks like all Huawei Android 6's do this).

Huawei has its own implementation of freezing apps' background processing (Protected apps). From the users reports I have confirmed that my app has an exception in the Huawei's protected apps and also in the Android 6's Doze mode. The app works OK but after exactly 15 minutes with display off my app stops sending messages to the connected Android Wear watch. My app can also record received notifications history and nothing arrives after the 15 minutes... until the phone's display is turned on and my app is opened. After that all the notifications that should have arrived while the phone's display was off arrive into my NotificationListenerService implementation and are sent to the watch, all at once. This is also confirmed with the recorded history.

Any ideas how to fix this for these phones, especially the Huawei Mate 8 with Android 6 with Doze mode?

What is the correct behaviour of the NotificationListenerService while the device is in the doze mode and/or the app is in the standby mode?

EDIT

Users have also confirmed that their phones are not in a power saving mode which also affects background apps and their services. This bug looks like Huawei exclusive because no Nexus users have reported this and my OnePlus One with M is not doing this either. Also N preview works good on Nexus devices.

EDIT 2

I have added an optional foreground service (startForeground()) so my app has a permanent notification in the notification center, thus my app should be excluded from every battery optimization. For the foreground service notification I used a priority of NotificationCompat.PRIORITY_MIN and I added the Notification.FLAG_ONGOING_EVENT flag. This helped a bit on the Huawei phones but not much, now the delayed notifications arrive into my NotificationListenerService right after the screen is turned-on instead after opening my app. I do not use the startForeground() in my NotificationListenerService but in another Service because I have no control about its lifecycle.

like image 819
shelll Avatar asked Apr 27 '16 20:04

shelll


1 Answers

For Huawei devices (not sure if applies to all Huawei devices), you need to request for Protected Apps permission in order for your app to not be freezed when it goes into the background.

To detect if a Huawei device has Protected Apps permission:

private boolean hasProtectedAppsSetting() {
    Intent intent = new Intent();
    intent.setClassName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity");

    List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent,
            PackageManager.MATCH_DEFAULT_ONLY);
    return list.size() > 0;
}

To bring up Huawei Protected Apps settings page:

private void showProtectedAppsSetting() {
    try {
        String cmd = "am start -n com.huawei.systemmanager/.optimize.process.ProtectActivity";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            cmd += " --user " + getUserSerial();
        }
        Runtime.getRuntime().exec(cmd);
    } catch (IOException ignored) {
    }
}

private String getUserSerial() {
    //noinspection ResourceType
    Object userManager = getSystemService("user");
    if (null == userManager) return "";

    try {
        Method myUserHandleMethod = android.os.Process.class.getMethod("myUserHandle", (Class<?>[]) null);
        Object myUserHandle = myUserHandleMethod.invoke(android.os.Process.class, (Object[]) null);
        Method getSerialNumberForUser = userManager.getClass().getMethod("getSerialNumberForUser", myUserHandle.getClass());
        long userSerial = (Long) getSerialNumberForUser.invoke(userManager, myUserHandle);
        return String.valueOf(userSerial);
    } catch (NoSuchMethodException | IllegalArgumentException | InvocationTargetException | IllegalAccessException ignored) {
    }
    return "";
}

Unfortunately I've not found any way to check if user have granted your app as a Protected App. Please share if anybody knows :)

Reference: http://ndroid.info/ldquo_protected_appsrdquo_setting_on_huawei_phones_and_how_to_handle_it

like image 153
avelyne Avatar answered Oct 02 '22 00:10

avelyne