diff --git a/xwords4/android/app/src/main/AndroidManifest.xml b/xwords4/android/app/src/main/AndroidManifest.xml
index 810e8b25a..ccc7396e2 100644
--- a/xwords4/android/app/src/main/AndroidManifest.xml
+++ b/xwords4/android/app/src/main/AndroidManifest.xml
@@ -179,15 +179,16 @@
-
-
+
+
diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BTService.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BTService.java
index 61b033bd3..8b1f3a9b1 100644
--- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BTService.java
+++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BTService.java
@@ -21,6 +21,8 @@
package org.eehouse.android.xw4;
import android.app.Activity;
+import android.app.Notification;
+import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass.Device.Major;
@@ -29,7 +31,8 @@ import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.Intent;
-import android.support.v4.app.JobIntentService;
+import android.os.Build;
+import android.support.v4.app.NotificationCompat;
import junit.framework.Assert;
@@ -66,6 +69,8 @@ public class BTService extends XWService {
private static final int BT_PROTO = BT_PROTO_JSONS; // change in a release or two
private enum BTAction { _NONE,
+ START_FOREGROUND,
+ START_BACKGROUND,
SCAN,
INVITE,
SEND,
@@ -93,6 +98,8 @@ public class BTService extends XWService {
private static final String BT_NAME_KEY = "BT_NAME";
private static final String BT_ADDRESS_KEY = "BT_ADDRESS";
+ private static Boolean sInForeground;
+
private enum BTCmd {
BAD_PROTO,
PING,
@@ -225,12 +232,33 @@ public class BTService extends XWService {
return result;
}
+ private static void onAppStateChange( Context context, boolean inForeground )
+ {
+ if ( sInForeground == null || sInForeground != inForeground ) {
+ sInForeground = inForeground;
+
+ Intent intent =
+ getIntentTo( context,
+ inForeground ? BTAction.START_FOREGROUND
+ : BTAction.START_BACKGROUND );
+ startService( context, intent );
+ }
+ }
+
+ static void onAppToForeground( Context context )
+ {
+ onAppStateChange( context, true );
+ }
+
+ static void onAppToBackground( Context context )
+ {
+ onAppStateChange( context, false );
+ }
+
public static void startService( Context context )
{
if ( XWApp.BTSUPPORTED ) {
startService( context, new Intent( context, BTService.class ) );
- // didn't help
- // startService( context, new Intent( /*context, BTService.class*/ ) );
}
}
@@ -322,17 +350,26 @@ public class BTService extends XWService {
{
Log.d( TAG, "startService(%s)", intent );
- if ( false ) {
- // requires asking for Manifest.permission.FOREGROUND_SERVICE
+ if ( ! sInForeground && canRunForegroundService() ) {
context.startForegroundService( intent );
- } else {
- JobIntentService.enqueueWork( context, BTService.class, 1111, intent );
+ } else if ( sInForeground || Build.VERSION.SDK_INT < Build.VERSION_CODES.O ) {
+ context.startService( intent );
}
}
+ // We can run a foreground service IIF the OS version is recent enough AND
+ // user hasn't said not to do it.
+ private static boolean canRunForegroundService()
+ {
+ // added in API level 26
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+ // && Prefs.runForegroundServiceEnabled( context, true )
+ ;
+ }
+
private static Intent getIntentTo( Context context, BTAction cmd )
{
- Intent intent = new Intent( /*context, BTService.class*/ );
+ Intent intent = new Intent( context, BTService.class );
intent.putExtra( CMD_KEY, cmd.ordinal() );
return intent;
}
@@ -358,7 +395,13 @@ public class BTService extends XWService {
@Override
public int onStartCommand( Intent intent, int flags, int startId )
{
- return handleCommand( intent );
+ int result = handleCommand( intent );
+
+ if ( Service.START_STICKY == result && !sInForeground ) {
+ startForeground();
+ }
+
+ return result;
}
private int handleCommand( Intent intent )
@@ -375,6 +418,12 @@ public class BTService extends XWService {
BTAction cmd = BTAction.values()[ordinal];
Log.i( TAG, "onStartCommand; cmd=%s", cmd.toString() );
switch( cmd ) {
+ case START_FOREGROUND:
+ stopForeground( true ); // Kill the notification
+ // FALLTHRU
+ case START_BACKGROUND:
+ break;
+
case CLEAR:
String[] btAddrs = intent.getStringArrayExtra( CLEAR_KEY );
clearDevs( btAddrs );
@@ -450,11 +499,21 @@ public class BTService extends XWService {
return result;
} // handleCommand()
- @Override
- protected void onHandleWork( Intent intent )
+ private void startForeground()
{
- Log.e( TAG, "onHandleWork(%s)", intent );
- /*(void)*/handleCommand( intent );
+ Intent notifIntent = GamesListDelegate.makeBackgroundIntent( this );
+ PendingIntent pendIntent = PendingIntent
+ .getActivity(this, Utils.nextRandomInt(), notifIntent, PendingIntent.FLAG_ONE_SHOT);
+ Notification notification =
+ new NotificationCompat.Builder(this, Utils.CHANNEL_ID)
+ .setSmallIcon( R.drawable.notify )
+ .setContentTitle( BTService.class.getSimpleName() )
+ .setContentText("listening for bluetooth messages...")
+ .setContentIntent(pendIntent)
+ .build();
+
+ Log.d( TAG, "calling startForeground()" );
+ startForeground( 1337, notification );
}
private class BTListenerThread extends Thread {
diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GamesListDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GamesListDelegate.java
index 086c6cff3..16077063c 100644
--- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GamesListDelegate.java
+++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GamesListDelegate.java
@@ -2665,6 +2665,12 @@ public class GamesListDelegate extends ListDelegateBase
return intent;
}
+ public static Intent makeBackgroundIntent( Context context )
+ {
+ Intent intent = makeSelfIntent( context );
+ return intent;
+ }
+
public static Intent makeRowidIntent( Context context, long rowid )
{
Intent intent = makeSelfIntent( context );
diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayService.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayService.java
index 8082adaef..b89c623eb 100644
--- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayService.java
+++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayService.java
@@ -25,7 +25,6 @@ import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
-import android.support.v4.app.JobIntentService;
import android.text.TextUtils;
import junit.framework.Assert;
@@ -201,10 +200,9 @@ public class RelayService extends XWService
Log.d( TAG, "startService(%s)", intent );
if ( false ) {
- // requires asking for Manifest.permission.FOREGROUND_SERVICE
context.startForegroundService( intent );
} else {
- JobIntentService.enqueueWork( context, RelayService.class, 1112, intent );
+ context.startService( intent );
}
}
@@ -391,13 +389,6 @@ public class RelayService extends XWService
super.onDestroy();
}
- @Override
- protected void onHandleWork( Intent intent )
- {
- Log.e( TAG, "onHandleWork(%s)", intent );
- handleCommand( intent );
- }
-
// NetStateCache.StateChangedIf interface
public void onNetAvail( boolean nowAvailable )
{
diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/Utils.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/Utils.java
index 96f64f19b..8bcfbf672 100644
--- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/Utils.java
+++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/Utils.java
@@ -84,7 +84,7 @@ public class Utils {
private static final String TAG = Utils.class.getSimpleName();
public static final int TURN_COLOR = 0x7F00FF00;
- private static final String CHANNEL_ID = BuildConfig.APPLICATION_ID + "_channel_id";
+ static final String CHANNEL_ID = BuildConfig.APPLICATION_ID + "_channel_id";
private static final String DB_PATH = "XW_GAMES";
private static final String HIDDEN_PREFS = "xwprefs_hidden";
diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWApp.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWApp.java
index 307b1230f..7927c4f65 100644
--- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWApp.java
+++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWApp.java
@@ -94,16 +94,23 @@ public class XWApp extends Application implements LifecycleObserver {
}
UpdateCheckReceiver.restartTimer( this );
- BTService.startService( this );
RelayService.startService( this );
GCMIntentService.init( this );
WiDirWrapper.init( this );
}
@OnLifecycleEvent(ON_ANY)
- public void onAny(LifecycleOwner source, Lifecycle.Event event)
+ public void onAny( LifecycleOwner source, Lifecycle.Event event )
{
- Log.d( TAG, "onAny(%s, %s)", source, event );
+ Log.d( TAG, "onAny(%s)", event );
+ switch( event ) {
+ case ON_RESUME:
+ BTService.onAppToForeground( this );
+ break;
+ case ON_STOP:
+ BTService.onAppToBackground( this );
+ break;
+ }
}
// This is called on emulator only, but good for ensuring no memory leaks
diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWService.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWService.java
index bd045895a..62e680abf 100644
--- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWService.java
+++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWService.java
@@ -23,9 +23,7 @@ package org.eehouse.android.xw4;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
-import android.os.Build;
import android.os.IBinder;
-import android.support.v4.app.JobIntentService;
import junit.framework.Assert;
@@ -39,7 +37,7 @@ import org.eehouse.android.xw4.jni.UtilCtxtImpl;
import java.util.HashSet;
import java.util.Set;
-abstract class XWService extends JobIntentService {
+abstract class XWService extends Service {
private static final String TAG = XWService.class.getSimpleName();
public static enum ReceiveResult { OK, GAME_GONE, UNCONSUMED };
@@ -48,21 +46,10 @@ abstract class XWService extends JobIntentService {
private UtilCtxt m_utilCtxt;
- // @Override
- // public IBinder onBind( Intent intent )
- // {
- // IBinder result = null;
- // if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ) {
- // result = super.onBind( intent );
- // }
- // return result;
- // }
-
@Override
- protected void onHandleWork(Intent intent)
+ public IBinder onBind( Intent intent )
{
- Log.e( TAG, "%s.onHandleWork(%s); dropping!!!", getClass().getSimpleName(),
- intent );
+ return null;
}
public final static void setListener( MultiService.MultiEventListener li )