From 271d43808f85a421353fc01f27aa84339b3fa68b Mon Sep 17 00:00:00 2001 From: Eric House Date: Tue, 4 Dec 2018 19:58:19 -0800 Subject: [PATCH] kill foreground service on a timer reset timer on receiving meaningful data and on moving app to background. If it fires and we're in background, kill the service. (There's currently no way to restart it except bringing the app into the foreground. Fixing that's coming.) --- .../org/eehouse/android/xw4/BTService.java | 60 ++++++++++++++++++- .../java/org/eehouse/android/xw4/DBUtils.java | 4 +- 2 files changed, 59 insertions(+), 5 deletions(-) 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 307297ed0..530e658fe 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 @@ -32,9 +32,10 @@ import android.bluetooth.BluetoothSocket; import android.content.Context; import android.content.Intent; import android.os.Build; +import android.os.Handler; +import android.os.SystemClock; import android.support.v4.app.NotificationCompat; - import org.eehouse.android.xw4.MultiService.DictFetchOwner; import org.eehouse.android.xw4.MultiService.MultiEvent; import org.eehouse.android.xw4.jni.CommsAddrRec; @@ -77,6 +78,8 @@ import java.util.concurrent.TimeUnit; public class BTService extends XWService { private static final String TAG = BTService.class.getSimpleName(); private static final String BOGUS_MARSHMALLOW_ADDR = "02:00:00:00:00:00"; + private static final String KEY_KEEPALIVE_UNTIL_SECS = "keep_secs"; + private static int DEFAULT_KEEPALIVE_SECONDS = 60 * 1; // 1 minute for testing; maybe 15 on ship? private static final long RESEND_TIMEOUT = 5; // seconds private static final int MAX_SEND_FAIL = 3; @@ -187,6 +190,8 @@ public class BTService extends XWService { private BTListenerThread m_listener; private BTSenderThread m_sender; private Notification m_notification; // make once use many + private Handler mHandler; + private static int s_errCount = 0; public static boolean BTAvailable() @@ -266,7 +271,9 @@ public class BTService extends XWService { private static boolean inForeground() { - return sInForeground != null && sInForeground; + boolean result = sInForeground != null && sInForeground; + // Log.d( TAG, "inForeground() => %b", result ); + return result; } static void onAppToForeground( Context context ) @@ -404,6 +411,7 @@ public class BTService extends XWService { @Override public void onCreate() { + mHandler = new Handler(); startForegroundIf(); BluetoothAdapter adapter = XWApp.BTSUPPORTED @@ -446,8 +454,10 @@ public class BTService extends XWService { switch( cmd ) { case START_FOREGROUND: stopForeground( true ); // Kill the notification - // FALLTHRU + break; case START_BACKGROUND: + noteLastUsed( this ); // prevent timer from killing immediately + setTimeoutTimer(); break; case CLEAR: @@ -581,6 +591,7 @@ public class BTService extends XWService { byte proto = inStream.readByte(); BTCmd cmd = BTCmd.values()[inStream.readByte()]; + Log.d( TAG, "BTListenerThread() got %s", cmd ); if ( protoOK( proto, cmd ) ) { switch( cmd ) { case PING: @@ -602,6 +613,7 @@ public class BTService extends XWService { break; } mService.updateStatusIn( true ); + noteLastUsed( mContext ); } else { DataOutputStream os = new DataOutputStream( socket.getOutputStream() ); @@ -1190,6 +1202,48 @@ public class BTService extends XWService { return dos; } + private static void noteLastUsed( Context context ) + { + Log.d( TAG, "noteLastUsed(" + context + ")" ); + synchronized (BTService.class) { + int nowSecs = (int)(SystemClock.uptimeMillis() / 1000); + int newKeepSecs = nowSecs + DEFAULT_KEEPALIVE_SECONDS; + DBUtils.setIntFor( context, KEY_KEEPALIVE_UNTIL_SECS, newKeepSecs ); + } + } + + private void setTimeoutTimer() + { + DbgUtils.assertOnUIThread(); + + if ( inForeground() ) { + // Let the timer die if we're in the foreground! + Log.d( TAG, "setTimeoutTimer(): in foreground; not resetting timer" ); + } else { + long dieTimeMillis; + synchronized (BTService.class) { + dieTimeMillis = 1000 * DBUtils.getIntFor( this, KEY_KEEPALIVE_UNTIL_SECS, 0 ); + } + long nowMillis = SystemClock.uptimeMillis(); + + if ( dieTimeMillis <= nowMillis ) { + Log.d( TAG, "setTimeoutTimer(): killing the thing" ); + stopListener(); + stopForeground(true); + } else { + mHandler.removeCallbacksAndMessages( this ); + mHandler.postAtTime( new Runnable() { + @Override + public void run() { + Log.d( TAG, "timeout timer fired" ); + setTimeoutTimer(); + } + }, this, dieTimeMillis ); + Log.d( TAG, "setTimeoutTimer(): set for %dms from now", dieTimeMillis - nowMillis ); + } + } + } + private static void logIOE( IOException ioe ) { Log.ex( TAG, ioe ); diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java index 700b918a8..173c0d05e 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java @@ -2394,7 +2394,7 @@ public class DBUtils { public static void setIntFor( Context context, String key, int value ) { - // Log.df( "DBUtils.setIntFor(key=%s, val=%d)", key, value ); + // Log.d( TAG, "DBUtils.setIntFor(key=%s, val=%d)", key, value ); String asStr = String.format( "%d", value ); setStringFor( context, key, asStr ); } @@ -2405,7 +2405,7 @@ public class DBUtils { if ( null != asStr ) { dflt = Integer.parseInt( asStr ); } - // Log.df( "DBUtils.getIntFor(key=%s)=>%d", key, dflt ); + // Log.d( TAG, "DBUtils.getIntFor(key=%s)=>%d", key, dflt ); return dflt; }