sforkowany z mirror/meshtastic-android
				
			workaround for slow booting Samsung phones
							rodzic
							
								
									33265c7c2e
								
							
						
					
					
						commit
						407a38594f
					
				|  | @ -146,5 +146,11 @@ dependencies { | ||||||
|     implementation('com.journeyapps:zxing-android-embedded:4.1.0') { transitive = false } |     implementation('com.journeyapps:zxing-android-embedded:4.1.0') { transitive = false } | ||||||
|     implementation 'com.google.zxing:core:3.4.0' |     implementation 'com.google.zxing:core:3.4.0' | ||||||
| 
 | 
 | ||||||
|  |     def work_version = "2.3.4" | ||||||
|  | 
 | ||||||
|  |     // Work Request - used to delay boot event handling | ||||||
|  |     // implementation "androidx.work:work-runtime:$work_version" | ||||||
|  |     implementation "androidx.work:work-runtime-ktx:$work_version" | ||||||
|  | 
 | ||||||
|     implementation project(':geeksville-androidlib') |     implementation project(':geeksville-androidlib') | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -674,10 +674,10 @@ class MainActivity : AppCompatActivity(), Logging, | ||||||
|         if (model.meshService != null) |         if (model.meshService != null) | ||||||
|             Exceptions.reportError("meshService was supposed to be null, ignoring (but reporting a bug)") |             Exceptions.reportError("meshService was supposed to be null, ignoring (but reporting a bug)") | ||||||
| 
 | 
 | ||||||
|         MeshService.startService(this)?.let { intent -> |         MeshService.startService(this) // Start the service so it stays running even after we unbind | ||||||
|             // ALSO bind so we can use the api | 
 | ||||||
|             mesh.connect(this, intent, Context.BIND_AUTO_CREATE + Context.BIND_ABOVE_CLIENT) |         // ALSO bind so we can use the api | ||||||
|         } |         mesh.connect(this, MeshService.intent, Context.BIND_AUTO_CREATE + Context.BIND_ABOVE_CLIENT) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private fun unbindMeshService() { |     private fun unbindMeshService() { | ||||||
|  |  | ||||||
|  | @ -8,8 +8,7 @@ import com.geeksville.android.Logging | ||||||
| 
 | 
 | ||||||
| class BootCompleteReceiver : BroadcastReceiver(), Logging { | class BootCompleteReceiver : BroadcastReceiver(), Logging { | ||||||
|     override fun onReceive(mContext: Context, intent: Intent) { |     override fun onReceive(mContext: Context, intent: Intent) { | ||||||
|         // FIXME - start listening for bluetooth messages from our device |         // start listening for bluetooth messages from our device | ||||||
|         info("Received boot complete announcement, starting mesh service") |         MeshService.startLater(mContext) | ||||||
|         MeshService.startService(mContext) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -16,6 +16,7 @@ import androidx.annotation.UiThread | ||||||
| import androidx.core.app.NotificationCompat | import androidx.core.app.NotificationCompat | ||||||
| import androidx.core.app.NotificationCompat.PRIORITY_MIN | import androidx.core.app.NotificationCompat.PRIORITY_MIN | ||||||
| import androidx.core.content.edit | import androidx.core.content.edit | ||||||
|  | import androidx.work.* | ||||||
| import com.geeksville.analytics.DataPair | import com.geeksville.analytics.DataPair | ||||||
| import com.geeksville.android.GeeksvilleApplication | import com.geeksville.android.GeeksvilleApplication | ||||||
| import com.geeksville.android.Logging | import com.geeksville.android.Logging | ||||||
|  | @ -33,6 +34,7 @@ import kotlinx.coroutines.* | ||||||
| import kotlinx.serialization.Serializable | import kotlinx.serialization.Serializable | ||||||
| import kotlinx.serialization.json.Json | import kotlinx.serialization.json.Json | ||||||
| import kotlinx.serialization.json.JsonConfiguration | import kotlinx.serialization.json.JsonConfiguration | ||||||
|  | import java.util.concurrent.TimeUnit | ||||||
| import kotlin.coroutines.CoroutineContext | import kotlin.coroutines.CoroutineContext | ||||||
| import kotlin.coroutines.EmptyCoroutineContext | import kotlin.coroutines.EmptyCoroutineContext | ||||||
| 
 | 
 | ||||||
|  | @ -67,33 +69,67 @@ class MeshService : Service(), Logging { | ||||||
|         class NodeNumNotFoundException(id: Int) : Exception("NodeNum not found $id") |         class NodeNumNotFoundException(id: Int) : Exception("NodeNum not found $id") | ||||||
|         class NotInMeshException() : Exception("We are not yet in a mesh") |         class NotInMeshException() : Exception("We are not yet in a mesh") | ||||||
| 
 | 
 | ||||||
|         /// Helper function to start running our service, returns the intent used to reach it |         /** A little helper that just calls startService | ||||||
|         /// or null if the service could not be started (no bluetooth or no bonded device set) |          */ | ||||||
|         fun startService(context: Context): Intent? { |         class ServiceStarter(appContext: Context, workerParams: WorkerParameters) : | ||||||
|  |             Worker(appContext, workerParams) { | ||||||
|  | 
 | ||||||
|  |             override fun doWork(): Result = try { | ||||||
|  |                 startService(this.applicationContext) | ||||||
|  | 
 | ||||||
|  |                 // Indicate whether the task finished successfully with the Result | ||||||
|  |                 Result.success() | ||||||
|  |             } catch (ex: Exception) { | ||||||
|  |                 errormsg("failure starting service, will retry", ex) | ||||||
|  |                 Result.retry() | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /** | ||||||
|  |          * Just after boot the android OS is super busy, so if we call startForegroundService then, our | ||||||
|  |          * thread might be stalled long enough to expose this google/samsung bug: | ||||||
|  |          * https://issuetracker.google.com/issues/76112072#comment56 | ||||||
|  |          */ | ||||||
|  |         fun startLater(context: Context) { | ||||||
|  |             info("Received boot complete announcement, starting mesh service in one minute") | ||||||
|  |             val delayRequest = OneTimeWorkRequestBuilder<ServiceStarter>() | ||||||
|  |                 .setInitialDelay(1, TimeUnit.MINUTES) | ||||||
|  |                 .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES) | ||||||
|  |                 .addTag("startLater") | ||||||
|  |                 .build() | ||||||
|  | 
 | ||||||
|  |             WorkManager.getInstance(context).enqueue(delayRequest) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         val intent = Intent().apply { | ||||||
|  |             setClassName( | ||||||
|  |                 "com.geeksville.mesh", | ||||||
|  |                 "com.geeksville.mesh.service.MeshService" | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// Helper function to start running our service | ||||||
|  |         fun startService(context: Context) { | ||||||
|             // bind to our service using the same mechanism an external client would use (for testing coverage) |             // bind to our service using the same mechanism an external client would use (for testing coverage) | ||||||
|             // The following would work for us, but not external users |             // The following would work for us, but not external users | ||||||
|             //val intent = Intent(this, MeshService::class.java) |             //val intent = Intent(this, MeshService::class.java) | ||||||
|             //intent.action = IMeshService::class.java.name |             //intent.action = IMeshService::class.java.name | ||||||
|             val intent = Intent() | 
 | ||||||
|             intent.setClassName( |  | ||||||
|                 "com.geeksville.mesh", |  | ||||||
|                 "com.geeksville.mesh.service.MeshService" |  | ||||||
|             ) |  | ||||||
| 
 | 
 | ||||||
|             // Before binding we want to explicitly create - so the service stays alive forever (so it can keep |             // Before binding we want to explicitly create - so the service stays alive forever (so it can keep | ||||||
|             // listening for the bluetooth packets arriving from the radio.  And when they arrive forward them |             // listening for the bluetooth packets arriving from the radio.  And when they arrive forward them | ||||||
|             // to Signal or whatever. |             // to Signal or whatever. | ||||||
| 
 | 
 | ||||||
|             logAssert( |             info("Trying to start service") | ||||||
|  |             val compName = | ||||||
|                 (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |                 (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||||||
|                     // we have some samsung devices failing with https://issuetracker.google.com/issues/76112072#comment56 not sure what the fix is yet |  | ||||||
|                     context.startForegroundService(intent) |                     context.startForegroundService(intent) | ||||||
|                 } else { |                 } else { | ||||||
|                     context.startService(intent) |                     context.startService(intent) | ||||||
|                 }) != null |                 }) | ||||||
|             ) |  | ||||||
| 
 | 
 | ||||||
|             return intent |             if (compName == null) | ||||||
|  |                 throw Exception("Failed to start service") | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Ładowanie…
	
		Reference in New Issue
	
	 geeksville
						geeksville