Check Google Play Services Availability on Android

It should be called on onResume:

    /**
     * A utility method to validate that the appropriate version of the Google Play Services is
     * available on the device. If not, it will open a dialog to address the issue. The dialog
     * displays a localized message about the error and upon user confirmation (by tapping on
     * dialog) will direct them to the Play Store if Google Play services is out of date or
     * missing, or to system settings if Google Play services is disabled on the device.
     */
    public static boolean checkGooglePlayServices(final Activity activity) {
        final int googlePlayServicesCheck = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(
                activity);
        switch (googlePlayServicesCheck) {
            case ConnectionResult.SUCCESS:
                return true;
            default:

                Dialog dialog = GoogleApiAvailability.getInstance().getErrorDialog(activity, googlePlayServicesCheck, 0);
                dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialog) {
                        activity.finish();
                    }
                });

                dialog.show();
        }
        return false;
    }

References
https://www.programcreek.com/java-api-examples/?api=com.google.android.gms.common.GoogleApiAvailability

Interprocess Communication between Activity and Service using Messenger on Android

MyService

public class MyService extends Service {

    private final int JOB1 = 1;
    private final int JOB1Response = 2;
    private final int JOB2 = 3;
    private final int JOB2Response = 4;
    Messenger messenger = new Messenger(new MyServiceHandler());

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }


    class MyServiceHandler extends Handler {

        Message MSG;
        String message;
        Bundle bundle = new Bundle();

        @Override
        public void handleMessage(Message msg) {

            try {

                switch (msg.what) {
                    case JOB1:

                        message = "This is the first message from service";
                        MSG = Message.obtain(null, JOB1Response);
                        bundle.putString("responseMessage", message);
                        MSG.setData(bundle);
                        msg.replyTo.send(MSG);

                        break;

                    case JOB2:

                        message = "This is the second message from service";
                        MSG = Message.obtain(null, JOB2Response);
                        bundle.putString("responseMessage", message);
                        MSG.setData(bundle);
                        msg.replyTo.send(MSG);

                        break;

                    default:
                        super.handleMessage(msg);
                }

            } catch (Exception ex) {
                ex.printStackTrace();
            }

        }
    }
}

MainActivity

public class MainActivity extends AppCompatActivity {

    private final int JOB1 = 1;
    private final int JOB1Response = 2;
    private final int JOB2 = 3;
    private final int JOB2Response = 4;
    Messenger messenger = null;
    boolean isBound = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this, MyService.class);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }


    ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            messenger = new Messenger(service);
            isBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            messenger = null;
            isBound = false;
        }
    };

    // JOB1
    private void sendMessage1() {
        try {
            if (isBound){
                  Message msg = Message.obtain(null, JOB1);
                  msg.replyTo = new Messenger(new MainActivityHandler());
                  messenger.send(msg);
            }
           
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    // JOB2
    private void sendMessage2() {
        try {
            if (isBound){
                  Message msg = Message.obtain(null, JOB2);
                  msg.replyTo = new Messenger(new MainActivityHandler());
                  messenger.send(msg);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void LogMessage1(String msg)
    {
        Log.d("MSG",msg);
    }

    @Override
    protected void onStop() {

        unbindService(serviceConnection);
        isBound = false;
        messenger = null;

        super.onStop();
    }

    class MainActivityHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {

            String message;

            switch (msg.what) {
                case JOB1Response:
                    message = msg.getData().getString("responseMessage");

                    // do something here

                    LogMessage1(message);

                    break;
                case JOB2Response:
                    message = msg.getData().getString("responseMessage");

                    // do something here
                    break;
                default:
                    super.handleMessage(msg);
            }


        }
    }
}

AndroidManifest.xml

<service android:name=".MyService" android:process=":remote"/>

References
https://www.youtube.com/watch?v=yAmnirP0d4U&t=0s&list=PLshdtb5UWjSp0879mLeCsDQN6L73XBZTk
https://developer.android.com/guide/components/bound-services

Schedule tasks with AlarmManager on Android

Receiver Class

public class MyAlarmReceiver extends BroadcastReceiver {

    private AlarmManager alarmManager;
    private PowerManager powerManager;
    private PowerManager.WakeLock wakeLock;

    @Override
    public void onReceive(Context context, Intent intent) {

        try {
            powerManager = (PowerManager) context.getSystemService(POWER_SERVICE);
            wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TimeTickWakeLog");
            wakeLock.acquire(5 * 1000);

            MyLog.d("alarm manager : begin onReceive");
        } catch (Exception ex) {
            ex.printStackTrace();
            MyLog.ex(ex);

            if (wakeLock != null) {
                wakeLock.release();
                powerManager = null;
                wakeLock = null;
            }
        }

        try {
            int isServiceRunning = 0;
            ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
            for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
                if (MyMqttService.class.getName().equals(service.service.getClassName())) {

                    // service is running
                    isServiceRunning++;
                }
            }

            if (isServiceRunning == 0) {
                // service is not running, start it
                Intent serviceIntent = new Intent(context, MyMqttService.class);
                context.startService(serviceIntent);
            }

            // connect to mqtt broker if needed
            if (Statics.isAppInBackground()) {

                EventBus.getDefault().post(new ReconnectMqttEvent());
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            MyLog.ex(ex);
        }


        // the reason for separating try/catches is to insure next alarm manager will be scheduled
        try {
            // region reschedule alarm manager
            long timeToWait = 60 * 1000;

            alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
            Intent myIntent = new Intent(context, MyAlarmReceiver.class);
            PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, myIntent, 0);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                alarmManager.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                        SystemClock.elapsedRealtime() + timeToWait, alarmIntent);
            } else {
                alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                        SystemClock.elapsedRealtime() + timeToWait, alarmIntent);
            }
            // endregion


            MyLog.d("alarm manager : end onReceive");

            if (wakeLock != null) {
                wakeLock.release();
                powerManager = null;
                wakeLock = null;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            MyLog.ex(ex);

            if (wakeLock != null) {
                wakeLock.release();
                powerManager = null;
                wakeLock = null;
            }
        }
    }
}

Manifest file

        <receiver android:name=".MyAlarmReceiver">

        </receiver>

onCreate of Service

        // region schedule alarm manager for the first time

        long timeToWait = 60 * 1000;

        alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(this, MyAlarmReceiver.class);
        PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            alarmManager.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                    SystemClock.elapsedRealtime() + timeToWait, alarmIntent);
        } else {
            alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                    SystemClock.elapsedRealtime() + timeToWait, alarmIntent);
        }
        // endregion

Rereferences
https://developer.android.com/training/scheduling/alarms
https://stackoverflow.com/questions/4459058/alarm-manager-example
https://www.javatpoint.com/android-alarmmanager

Listening to android.os.action.DEVICE_IDLE_MODE_CHANGED

public class IdleModeReceiver extends BroadcastReceiver {

    private PowerManager powerManager;
    private PowerManager.WakeLock wakeLock;

    @TargetApi(Build.VERSION_CODES.M)
    @Override
    public void onReceive(Context context, Intent intent) {
        try {
            powerManager = (PowerManager) context.getSystemService(POWER_SERVICE);
            wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TimeTickWakeLog");
            wakeLock.acquire(30 * 1000);

            if (powerManager.isDeviceIdleMode()) {
                // the device is now in doze mode

                MyLog.d("power manager : doze mode");
            }
            else if (powerManager.isInteractive()){

                // the device is in iteractive mode

                MyLog.d("power manager : interactive mode");

            }
            else if (powerManager.isPowerSaveMode()) {
                // the device is in power save mode
                MyLog.d("power manager : power save mode");
            }

            if (wakeLock != null) {
                wakeLock.release();
                powerManager = null;
                wakeLock = null;
            }
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
            MyLog.ex(ex);
            if (wakeLock != null) {
                wakeLock.release();
                powerManager = null;
                wakeLock = null;
            }
        }

    }
}

for older devices add to manifest file:

        <receiver android:name=".IdleModeReceiver">
            <intent-filter>
                <action android:name=" android.os.action.DEVICE_IDLE_MODE_CHANGED" />
            </intent-filter>
        </receiver>

for new devices:

private IdleModeReceiver idleModeReceiver = new IdleModeReceiver();

        // register idle change
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            IntentFilter filter = new IntentFilter();
            filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);

            registerReceiver(idleModeReceiver, filter);
        }

References
https://developer.android.com/reference/android/os/PowerManager
https://stackoverflow.com/questions/31559698/android-m-listening-to-android-os-action-device-idle-mode-changed

Optimize for Doze and App Standby

    private boolean isIntentAvailable(@NonNull Context context, @NonNull Intent intent) {
        return context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
    }
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
                String packageName = getPackageName();
                Intent batteryIgnoreIntent = new Intent("android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS");
                batteryIgnoreIntent.setData(Uri.parse("package:" + packageName));
                boolean isIgnoringBatteryOptimizations = pm.isIgnoringBatteryOptimizations(packageName);

                if (!isIgnoringBatteryOptimizations) {

                    if (isIntentAvailable(MainActivity.this, batteryIgnoreIntent)) {
                        Intent intent = new Intent();
                        intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
                        intent.setData(Uri.parse("package:" + packageName));
                        startActivity(intent);
                    } else {
                        Intent intent = new Intent();
                        intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
                        startActivity(intent);
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            MyLog.ex(ex);
        }

Testing your app with Doze

adb shell dumpsys deviceidle enable

Force the system into idle mode by running the following command:

adb shell dumpsys deviceidle force-idle

When ready, exit idle mode by running the following command:

adb shell dumpsys deviceidle unforce

Force the app into App Standby mode by running the following commands:

adb shell dumpsys battery unplug
adb shell am set-inactive <packageName> true

Simulate waking your app using the following commands:

adb shell am set-inactive <packageName> false
adb shell am get-inactive <packageName>

References
https://www.bignerdranch.com/blog/choosing-the-right-background-scheduler-in-android/
https://developer.android.com/training/monitoring-device-state/doze-standby#support_for_other_use_cases
https://developer.android.com/topic/performance/scheduling
https://www.bignerdranch.com/blog/diving-into-doze-mode-for-developers/
https://stackoverflow.com/questions/48805376/how-solve-a-fatal-exception-in-android-content-activitynotfoundexception-error
https://stackoverflow.com/questions/32627342/how-to-whitelist-app-in-doze-mode-android-6-0
https://stackoverflow.com/questions/36457524/can-not-switch-to-doze-mode
https://stackoverflow.com/questions/33709046/wake-lock-disabled-in-foreground-service-with-doze-mode-new-battery-optimizati

Start Android application on boot

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<receiver android:name="MyStartServiceReceiver" >
   <intent-filter>
      <action android:name="android.intent.action.BOOT_COMPLETED" />
   </intent-filter>
</receiver>
public class MyStartServiceReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {

        try {
            if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
                Intent serviceIntent = new Intent(context, MyMqttService.class);
                context.startService(serviceIntent);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            MyLog.ex(ex);
        }
    }
}

Keep the device awake on Android using PowerManager

<uses-permission android:name="android.permission.WAKE_LOCK" />
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
        "MyWakelockTag");
wakeLock.acquire();
wakelock.release()

keep wakeLock for whole app

public class MyApp extends Application 
{
    private static final String TAG = MyApp.class.getSimpleName();
    private PowerManager.WakeLock mWakeLock = null;

    @Override
    public void onCreate() {
        super.onCreate();

        final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
        mWakeLock.acquire();
    }

    @Override
    public void onTerminate() {
        if (mWakeLock.isHeld())
            mWakeLock.release();
        super.onTerminate();
    }
}

or

Use a broadcast receiver that keeps the device awake

References
https://developer.android.com/training/scheduling/wakelock
https://developer.android.com/topic/performance/vitals/wakelock
https://stackoverflow.com/questions/9000563/partial-wake-lock-is-not-working