Skip to content

Commit

Permalink
Remove AppState and rework DefaultLifecycleObserver use
Browse files Browse the repository at this point in the history
Quest to prevent IllegalStateException when launching service believing app is in foreground while in background
  • Loading branch information
courville committed Dec 15, 2024
1 parent 8594a37 commit 96a2970
Show file tree
Hide file tree
Showing 14 changed files with 172 additions and 286 deletions.
87 changes: 22 additions & 65 deletions src/com/archos/mediacenter/utils/trakt/TraktService.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@
import android.provider.BaseColumns;
import android.widget.Toast;

import com.archos.mediacenter.utils.AppState;
import com.archos.mediacenter.utils.trakt.Trakt.Status;
import com.archos.mediacenter.utils.videodb.IndexHelper;
import com.archos.mediacenter.utils.videodb.VideoDbInfo;
import com.archos.medialib.R;
import com.archos.environment.NetworkState;
Expand All @@ -64,22 +62,15 @@

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.DayOfWeek;
import org.threeten.bp.Instant;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.OffsetDateTime;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.temporal.TemporalAdjusters;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

public class TraktService extends Service implements DefaultLifecycleObserver {

Expand Down Expand Up @@ -133,6 +124,8 @@ public class TraktService extends Service implements DefaultLifecycleObserver {

private static final long TRAKT_SYNC_DELAY = 30; // in sec

private static volatile boolean isForeground = false;

private NetworkState networkState = null;
private PropertyChangeListener propertyChangeListener = null;
public class TraktBinder extends Binder {
Expand Down Expand Up @@ -1254,18 +1247,15 @@ public void run() {

@Override
public void onCreate() {
// Register as a lifecycle observer
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
mNetworkState = NetworkState.instance(this);
mBackgroundHandlerThread = new HandlerThread(TAG);
mBackgroundHandlerThread.start();
mBackgroundHandler = new TraktHandler(mBackgroundHandlerThread.getLooper(), this);
mUiHandler = new Handler();
mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
// handles foregroud/background for networkState add/remove Listener
AppState.addOnForeGroundListener(mForeGroundListener);
handleForeGround(AppState.isForeGround());
super.onCreate();
// Register as a lifecycle observer
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}

@Override
Expand Down Expand Up @@ -1403,65 +1393,64 @@ private Intent prepareIntent(String action, long videoID, float progress, String
public void watching(long videoID, float progress) {
log.debug("watching: send INTENT_ACTION_WATCHING");
Intent intent = prepareIntent(INTENT_ACTION_WATCHING, videoID, progress, null);
if (AppState.isForeGround()) mContext.startService(intent);
if (isForeground) mContext.startService(intent);
}
public void watchingStop(long videoID, float progress) {
log.debug("watchingStop: send INTENT_ACTION_WATCHING_STOP");
Intent intent = prepareIntent(INTENT_ACTION_WATCHING_STOP, videoID, progress, null);
// do not check if isForeGround in this specific case in order to allow posting watch status when exiting
// video playback with home button to save state
//if (AppState.isForeGround()) mContext.startService(intent);
mContext.startService(intent);
// Should not check if isForeGround in this specific case in order to allow posting watch status when exiting
// video playback with home button to save state but with Android restrictions, do not do it because foreground services banned
if (isForeground) mContext.startService(intent);
}
public void watchingPause(long videoID, float progress) {
log.debug("watchingPause: send INTENT_ACTION_WATCHING_PAUSE");
Intent intent = prepareIntent(INTENT_ACTION_WATCHING_PAUSE, videoID, progress, null);
if (AppState.isForeGround()) mContext.startService(intent);
if (isForeground) mContext.startService(intent);
}
public void watching(VideoDbInfo videoInfo, float progress) {
log.debug("watching: send INTENT_ACTION_WATCHING");
Intent intent = prepareIntent(INTENT_ACTION_WATCHING, videoInfo, progress, null);
if (AppState.isForeGround()) mContext.startService(intent);
if (isForeground) mContext.startService(intent);
}
public void watchingStop(VideoDbInfo videoInfo, float progress) {
log.debug("watchingStop: send INTENT_ACTION_WATCHING_STOP");
Intent intent = prepareIntent(INTENT_ACTION_WATCHING_STOP, videoInfo, progress, null);
// do not check if isForeGround in this specific case in order to allow posting watch status when exiting
// video playback with home button to save state
//if (AppState.isForeGround()) mContext.startService(intent);
//if (isForeground) mContext.startService(intent);
mContext.startService(intent);
}
public void watchingPause(VideoDbInfo videoInfo, float progress) {
log.debug("watchingPause: send INTENT_ACTION_WATCHING_PAUSE");
Intent intent = prepareIntent(INTENT_ACTION_WATCHING_PAUSE, videoInfo, progress, null);
if (AppState.isForeGround()) mContext.startService(intent);
if (isForeground) mContext.startService(intent);
}
public void markAs(VideoDbInfo videoInfo, String traktAction) {
log.debug("markAs: send INTENT_ACTION_MARK_AS");
Intent intent = prepareIntent(INTENT_ACTION_MARK_AS, videoInfo, -1, traktAction);
if (AppState.isForeGround()) mContext.startService(intent);
if (isForeground) mContext.startService(intent);
}
public void wipe() {
log.debug("wipe: send INTENT_ACTION_WIPE");
Intent intent = prepareIntent(INTENT_ACTION_WIPE, null, -1, null);
if (AppState.isForeGround()) mContext.startService(intent);
if (isForeground) mContext.startService(intent);
}
public void wipeCollection() {
log.debug("wipeCollection: send INTENT_ACTION_WIPE_COLLECTION");
Intent intent = prepareIntent(INTENT_ACTION_WIPE_COLLECTION, null, -1, null);
if (AppState.isForeGround()) mContext.startService(intent);
if (isForeground) mContext.startService(intent);
}
public void fullSync() {
log.debug("fullSync: send INTENT_ACTION_SYNC");
Intent intent = prepareIntent(INTENT_ACTION_SYNC, null, -1, null);
intent.putExtra("flag_sync", FLAG_SYNC_FULL);
if (AppState.isForeGround()) mContext.startService(intent);
if (isForeground) mContext.startService(intent);
}
public void sync(int flag) {
log.debug("sync: send INTENT_ACTION_SYNC");
Intent intent = prepareIntent(INTENT_ACTION_SYNC, null, -1, null);
intent.putExtra("flag_sync", flag);
if (AppState.isForeGround()) mContext.startService(intent);
if (isForeground) mContext.startService(intent);
}
}

Expand All @@ -1477,43 +1466,6 @@ public static void onNewVideo(Context context) {
new Client(context, null, false).sync(FLAG_SYNC_TO_DB_WATCHED|FLAG_SYNC_TO_TRAKT|FLAG_SYNC_MOVIES|FLAG_SYNC_SHOWS);
}

public static void init() {
AppState.addOnForeGroundListener(sForeGroundListener);
}

// this one is static for CustomApplication init
private static final AppState.OnForeGroundListener sForeGroundListener = new AppState.OnForeGroundListener() {
@Override
public void onForeGroundState(Context applicationContext, boolean foreground) {
if (foreground && NetworkState.isNetworkConnected(applicationContext))
TraktService.sync(applicationContext, TraktService.FLAG_SYNC_AUTO);
}
};

// this one is non static for service use
private final AppState.OnForeGroundListener mForeGroundListener = new AppState.OnForeGroundListener() {
@Override
public void onForeGroundState(Context applicationContext, boolean foreground) {
if(foreground) {
log.debug("mForeGroundListener: foreground");
} else {
log.debug("mForeGroundListener: background");
}
handleForeGround(foreground);
}
};

protected void handleForeGround(boolean foreground) {
if (foreground) {
log.debug("handleForeGround: app now in ForeGround");
//addListener(false);
addListener();
} else {
log.debug("handleForeGround: app now in BackGround");
removeListener();
}
}

private void addListener() {
if (networkState == null) networkState = NetworkState.instance(getApplicationContext());
if (!mNetworkStateListenerAdded && propertyChangeListener != null) {
Expand All @@ -1536,6 +1488,7 @@ private void removeListener() {
public void onStop(LifecycleOwner owner) {
// App in background
log.debug("onStop: LifecycleOwner App in background");
isForeground = false;
cleanup();
stopSelf();
}
Expand All @@ -1544,6 +1497,10 @@ public void onStop(LifecycleOwner owner) {
public void onStart(LifecycleOwner owner) {
// App in foreground
log.debug("onStart: LifecycleOwner App in foreground");
isForeground = true;
if (NetworkState.isNetworkConnected(getApplicationContext()))
TraktService.sync(getApplicationContext(), TraktService.FLAG_SYNC_AUTO);
addListener();
}

}
21 changes: 1 addition & 20 deletions src/com/archos/mediaprovider/MediaRetrieverService.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,13 @@
import android.os.Message;
import android.util.Log;

import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleOwner;

import com.archos.medialib.IMediaMetadataRetriever;
import com.archos.medialib.MediaFactory;
import com.archos.medialib.MediaMetadata;

import java.lang.ref.WeakReference;

public class MediaRetrieverService extends Service implements DefaultLifecycleObserver {
public class MediaRetrieverService extends Service {

private static final String TAG = "MediaRetrieverService";
private static final boolean DBG = false;
Expand Down Expand Up @@ -71,7 +67,6 @@ public MediaMetadata getMetadata(String path) {
public void onCreate() {
super.onCreate();
if (DBG) Log.d(TAG, "onCreate");
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}

@Override
Expand Down Expand Up @@ -111,18 +106,4 @@ public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_NOT_STICKY;
}

@Override
public void onStop(LifecycleOwner owner) {
// App in background
if (DBG) Log.d(TAG, "onStop: LifecycleOwner App in background");
stopSelf();
}

@Override
public void onStart(LifecycleOwner owner) {
// App in foreground
if (DBG) Log.d(TAG, "onStart: LifecycleOwner App in foreground");
}

}
18 changes: 1 addition & 17 deletions src/com/archos/mediaprovider/MediaThumbnailService.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@
import android.os.Message;
import android.widget.Toast;

import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleOwner;

import com.archos.environment.ArchosUtils;
import com.archos.medialib.IMediaMetadataRetriever;
import com.archos.medialib.MediaFactory;
Expand All @@ -39,7 +35,7 @@

import java.lang.ref.WeakReference;

public class MediaThumbnailService extends Service implements DefaultLifecycleObserver {
public class MediaThumbnailService extends Service {

private static final Logger log = LoggerFactory.getLogger(MediaThumbnailService.class);

Expand Down Expand Up @@ -149,7 +145,6 @@ public static IMediaThumbnailService bind_sync(Context ctx) {
public void onCreate() {
super.onCreate();
log.debug("onCreate");
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}

@Override
Expand Down Expand Up @@ -193,15 +188,4 @@ public Bitmap getThumbnail(String path, int timeUs) {
}
return bitmap;
}

public void onStop(LifecycleOwner owner) {
// App in background
log.debug("onStop: LifecycleOwner App in background");
stopSelf();
}

public void onStart(LifecycleOwner owner) {
// App in foreground
log.debug("onStart: LifecycleOwner App in foreground");
}
}
40 changes: 29 additions & 11 deletions src/com/archos/mediaprovider/video/NetworkAutoRefresh.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,24 @@

package com.archos.mediaprovider.video;

import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;

import androidx.annotation.NonNull;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleOwner;
import androidx.preference.PreferenceManager;

import com.archos.environment.ArchosUtils;
import com.archos.filecorelibrary.ftp.Session;
import com.archos.filecorelibrary.sftp.SFTPSession;
import com.archos.mediacenter.filecoreextension.upnp2.UpnpServiceManager;
import com.archos.mediacenter.utils.AppState;
import com.archos.mediacenter.utils.ShortcutDbAdapter;
import com.archos.mediaprovider.ArchosMediaIntent;
import com.archos.environment.NetworkState;
Expand All @@ -42,10 +47,13 @@
/**
* Created by alexandre on 26/06/15.
*/
public class NetworkAutoRefresh extends BroadcastReceiver {
public class NetworkAutoRefresh extends BroadcastReceiver implements DefaultLifecycleObserver {

private static final Logger log = LoggerFactory.getLogger(NetworkAutoRefresh.class);

private static volatile boolean isForeground = false;
private static Application mApplication;

public static final String ACTION_RESCAN_INDEXED_FOLDERS = "com.archos.mediaprovider.video.NetworkAutoRefresh";
public static final String ACTION_FORCE_RESCAN_INDEXED_FOLDERS = "com.archos.mediaprovider.video.NetworkAutoRefresh_force";

Expand Down Expand Up @@ -133,15 +141,10 @@ else if(intent.getAction().equals(ACTION_RESCAN_INDEXED_FOLDERS)||
log.debug("onReceive: received rescan intent end");
}
}
private static final AppState.OnForeGroundListener sForeGroundListener = new AppState.OnForeGroundListener() {
@Override
public void onForeGroundState(Context applicationContext, boolean foreground) {
if (foreground&&autoRescanAtStart(applicationContext))
forceRescan(applicationContext);
}
};
public static void init() {
AppState.addOnForeGroundListener(sForeGroundListener);

public static void init(Application application) {
mApplication = application;
ProcessLifecycleOwner.get().getLifecycle().addObserver(new NetworkAutoRefresh());
}

public static void forceRescan(Context context){
Expand All @@ -164,4 +167,19 @@ public static void setAutoRescanAtStart(Context context, boolean autoRescanAtSta
public static int getRescanPeriod(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context).getInt(AUTO_RESCAN_PERIOD, 0);
}

@Override
public void onStart(@NonNull LifecycleOwner owner) {
log.debug("onStop: lifecycle foreground");
isForeground = true;
if (autoRescanAtStart(mApplication)) {
forceRescan(mApplication);
}
}

@Override
public void onStop(@NonNull LifecycleOwner owner) {
isForeground = false;
log.debug("onStop: lifecycle background");
}
}
1 change: 0 additions & 1 deletion src/com/archos/mediaprovider/video/NetworkRefreshJob.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ public class NetworkRefreshJob extends JobService implements DefaultLifecycleObs
public void onCreate() {
super.onCreate();
log.debug("onCreate");

// Register as a lifecycle observer
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
Expand Down
Loading

0 comments on commit 96a2970

Please sign in to comment.