package com.hokolinks.utils.lifecycle;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.os.Bundle;
import com.hokolinks.activity.HokoActivity;
import com.hokolinks.activity.HokoAppLinksActivity;
import com.hokolinks.utils.log.HokoLog;
import java.util.ArrayList;
import java.util.List;
/**
* A small wrapper around activity life cycles to provide actual Application lifecycle status with
* callbacks on background/foreground changes.
*/
public class ApplicationLifecycle {
/**
* Static instance to handle static callback registration
*/
private static ApplicationLifecycle sInstance;
private HokoApplicationStatus mApplicationStatus;
private List<ApplicationLifecycleCallback> mCallbacks;
/**
* Private initializer, starting on FOREGROUND since it is what actually makes sense.
*
* @param context A context.
*/
private ApplicationLifecycle(Context context) {
mCallbacks = new ArrayList<>();
mApplicationStatus = HokoApplicationStatus.FOREGROUND;
try {
registerActivityLifecycle(context);
} catch (NullPointerException e) {
HokoLog.e(e);
}
}
/**
* Retrieves the static instance for the ApplicationLifecycle handler.
*
* @param context A context.
* @return The static ApplicationLifecycle instance.
*/
private static ApplicationLifecycle getInstance(Context context) {
if (sInstance == null)
sInstance = new ApplicationLifecycle(context);
return sInstance;
}
/**
* The only public function. Allows the registration of application lifecycle callbacks, by
* passing a context and a callback. You can register multiple callbacks, they shall be executed
* in order of registration.
*
* @param context A context.
* @param callback A callback.
*/
public static void registerApplicationLifecycleCallback(
Context context, ApplicationLifecycleCallback callback) {
getInstance(context).registerApplicationLifecycleCallback(callback);
}
/**
* Registers an application lifecycle callback.
*
* @param callback A ApplicationLifecycleCallback instance.
*/
private void registerApplicationLifecycleCallback(ApplicationLifecycleCallback callback) {
mCallbacks.add(callback);
}
/**
* Method to be called when an Application onPause is detected.
* This will check the current application status is foreground, if it is it will be set as
* background and call all callbacks' onPause() method.
*/
private void onPause() {
if (mApplicationStatus == HokoApplicationStatus.FOREGROUND) {
mApplicationStatus = HokoApplicationStatus.BACKGROUND;
for (ApplicationLifecycleCallback callback : mCallbacks) {
callback.onPause();
}
}
}
/**
* Method to be called when an Application onResume is detected.
* This will check the current application status is background, if it is it will be set as
* foreground and call all callbacks' onResume() method.
*/
private void onResume() {
if (mApplicationStatus == HokoApplicationStatus.BACKGROUND) {
mApplicationStatus = HokoApplicationStatus.FOREGROUND;
for (ApplicationLifecycleCallback callback : mCallbacks) {
callback.onResume();
}
}
}
/**
* Background happens when an activity is paused and stopped without any resumes in the middle.
* Foreground might happen on every resume, it is only triggered when the application's state is
* BACKGROUND. Ignoring HokoActivity due to Intent flags.
*
* @param context A context.
*/
private void registerActivityLifecycle(Context context) {
if (context != null) {
Application application = (Application) context.getApplicationContext();
application.registerActivityLifecycleCallbacks(
new Application.ActivityLifecycleCallbacks() {
private ArrayList<HokoActivityStatus> statusHistory =
new ArrayList<>();
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
if (activity instanceof HokoActivity ||
activity instanceof HokoAppLinksActivity)
return;
if (statusHistory.size() != 0)
statusHistory.add(HokoActivityStatus.RESUMED);
onResume();
}
@Override
public void onActivityPaused(Activity activity) {
if (activity instanceof HokoActivity ||
activity instanceof HokoAppLinksActivity)
return;
statusHistory.add(HokoActivityStatus.PAUSED);
}
@Override
public void onActivityStopped(Activity activity) {
statusHistory.add(HokoActivityStatus.STOPPED);
handlePossibleBackground();
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
private void handlePossibleBackground() {
if (statusHistory.get(0) == HokoActivityStatus.PAUSED
&& statusHistory.get(1) == HokoActivityStatus.STOPPED) {
onPause();
}
statusHistory = new ArrayList<>();
}
});
} else {
throw new NullPointerException();
}
}
/**
* The Activity statuses that actually matter.
*/
private enum HokoActivityStatus {
PAUSED, RESUMED, STOPPED
}
/**
* The Application statuses for inner logic.
*/
private enum HokoApplicationStatus {
FOREGROUND, BACKGROUND
}
}