How the activity should be launched with android:launchMode

Use Cases Launch Mode Multiple Instances? Comments
Normal launches for most activities standard Yes Default. The system always creates a new instance of the activity in the target task and routes the intent to it.
singleTop Conditionally If an instance of the activity already exists at the top of the target task, the system routes the intent to that instance through a call to its onNewIntent() method, rather than creating a new instance of the activity.
Specialized launches
(not recommended for general use)
singleTask No The system creates the activity at the root of a new task and routes the intent to it. However, if an instance of the activity already exists, the system routes the intent to existing instance through a call to its onNewIntent()method, rather than creating a new one.
singleInstance No Same as “singleTask", except that the system doesn’t launch any other activities into the task holding the instance. The activity is always the single and only member of its task.

References
https://developer.android.com/guide/topics/manifest/activity-element#lmode

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

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

Modify Socket parameters of Mqtt Client

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

import javax.net.SocketFactory;

public class MySocketFactory extends SocketFactory {

    private SocketFactory socketFactory;
    private Socket socket;

    public MySocketFactory() {
        this.socketFactory = SocketFactory.getDefault();
    }

    public MySocketFactory(SocketFactory socketFactory) {
        this.socketFactory = socketFactory;
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException {
        socket = this.socketFactory.createSocket(host, port);
        modifySocket();
        return socket;
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
        socket = socketFactory.createSocket(host, port, localHost, localPort);
        modifySocket();
        return socket;
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        socket = socketFactory.createSocket(host, port);
        modifySocket();
        return socket;
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        socket = socketFactory.createSocket(address, port, localAddress, localPort);
        modifySocket();
        return socket;
    }

    @Override
    public Socket createSocket() throws IOException {
        socket = socketFactory.createSocket();
        modifySocket();
        return socket;
    }

    private void modifySocket() throws IOException {
        socket.setKeepAlive(true);
        socket.setSoTimeout(10 * 1000);
        socket.setSoLinger(true, 0);
        socket.setTcpNoDelay(true);
    }
}
String broker = Statics.broker;
// mqtt paho client id
clientId = MqttClient.generateClientId();
client = new MqttAndroidClient(MyMqttService.this, broker,
                        clientId, new MemoryPersistence());

MqttConnectOptions options = new MqttConnectOptions();
options.setAutomaticReconnect(false);
options.setCleanSession(true);
options.setUserName(""test");
options.setPassword("test".toCharArray());
options.setConnectionTimeout(20);
options.setKeepAliveInterval(0);

MySocketFactory mySocketFactory=new MySocketFactory();
options.setSocketFactory(mySocketFactory);