5353import com .smartdevicelink .R ;
5454import com .smartdevicelink .transport .RouterServiceValidator .TrustedListCallback ;
5555import com .smartdevicelink .transport .enums .TransportType ;
56+ import com .smartdevicelink .transport .utl .SdlDeviceListener ;
5657import com .smartdevicelink .util .AndroidTools ;
5758import com .smartdevicelink .util .DebugTool ;
5859import com .smartdevicelink .util .SdlAppInfo ;
@@ -85,6 +86,8 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver{
8586 private static final Object QUEUED_SERVICE_LOCK = new Object ();
8687 private static ComponentName queuedService = null ;
8788 private static Thread .UncaughtExceptionHandler foregroundExceptionHandler = null ;
89+ private static final Object DEVICE_LISTENER_LOCK = new Object ();
90+ private static SdlDeviceListener sdlDeviceListener ;
8891
8992 public int getRouterServiceVersion (){
9093 return SdlRouterService .ROUTER_SERVICE_VERSION_NUMBER ;
@@ -190,9 +193,6 @@ public void onListObtained(boolean successful) {
190193 });
191194 }
192195
193- }else {
194- //This was previously not hooked up, so let's leave it commented out
195- //onSdlDisabled(context);
196196 }
197197 return ;
198198 }else if (intent .getBooleanExtra (TransportConstants .PING_ROUTER_SERVICE_EXTRA , false )){
@@ -223,52 +223,97 @@ public void onListObtained(boolean successful) {
223223 }
224224 }
225225
226+ /**
227+ * This method will attempt to start the router service.
228+ * @param context to be used to start the service and send broadcasts
229+ * @param componentName the router service that should be started
230+ * @param altTransportWake if the alt transport flag should be set. Only used in debug
231+ * @param device the connected bluetooth device
232+ */
233+ private static void startRouterService (Context context , ComponentName componentName , boolean altTransportWake , BluetoothDevice device ) {
234+ if (componentName == null ) {
235+ return ;
236+ }
237+
238+ Intent serviceIntent = new Intent ();
239+ serviceIntent .setComponent (componentName );
240+
241+ if (altTransportWake ) {
242+ serviceIntent .setAction (TransportConstants .BIND_REQUEST_TYPE_ALT_TRANSPORT );
243+ }
244+
245+ if (device != null ) {
246+ serviceIntent .putExtra (BluetoothDevice .EXTRA_DEVICE , device );
247+ }
248+
249+ try {
250+ if (Build .VERSION .SDK_INT < Build .VERSION_CODES .O ) {
251+ context .startService (serviceIntent );
252+ } else {
253+ serviceIntent .putExtra (FOREGROUND_EXTRA , true );
254+ DebugTool .logInfo ("Attempting to startForegroundService - " + System .currentTimeMillis ());
255+ setForegroundExceptionHandler (); //Prevent ANR in case the OS takes too long to start the service
256+ context .startForegroundService (serviceIntent );
257+
258+ }
259+ //Make sure to send this out for old apps to close down
260+ SdlRouterService .LocalRouterService self = SdlRouterService .getLocalRouterService (serviceIntent , serviceIntent .getComponent ());
261+ Intent restart = new Intent (SdlRouterService .REGISTER_NEWER_SERVER_INSTANCE_ACTION );
262+ restart .putExtra (LOCAL_ROUTER_SERVICE_EXTRA , self );
263+ restart .putExtra (LOCAL_ROUTER_SERVICE_DID_START_OWN , true );
264+ context .sendBroadcast (restart );
265+
266+ } catch (SecurityException e ) {
267+ Log .e (TAG , "Security exception, process is bad" );
268+ }
269+ }
270+
226271 private boolean wakeUpRouterService (final Context context , final boolean ping , final boolean altTransportWake , final BluetoothDevice device ){
227- new ServiceFinder (context , context .getPackageName (), new ServiceFinder .ServiceFinderCallback () {
272+ new ServiceFinder (context , context .getPackageName (), new ServiceFinder .ServiceFinderCallback () {
228273 @ Override
229274 public void onComplete (Vector <ComponentName > routerServices ) {
230275 runningBluetoothServicePackage = new Vector <ComponentName >();
231276 runningBluetoothServicePackage .addAll (routerServices );
232277 if (runningBluetoothServicePackage .isEmpty ()) {
233278 //If there isn't a service running we should try to start one
234279 //We will try to sort the SDL enabled apps and find the one that's been installed the longest
235- Intent serviceIntent ;
236- List <SdlAppInfo > sdlAppInfoList = AndroidTools .querySdlAppInfo (context , new SdlAppInfo .BestRouterComparator ());
280+ final List <SdlAppInfo > sdlAppInfoList = AndroidTools .querySdlAppInfo (context , new SdlAppInfo .BestRouterComparator ());
281+ synchronized (DEVICE_LISTENER_LOCK ) {
282+ final boolean sdlDeviceListenerEnabled = SdlDeviceListener .isFeatureSupported (sdlAppInfoList );
283+ if (sdlDeviceListenerEnabled ) {
284+ String myPackage = context .getPackageName ();
285+ String routerServicePackage = null ;
286+ if (sdlAppInfoList != null && !sdlAppInfoList .isEmpty () && sdlAppInfoList .get (0 ).getRouterServiceComponentName () != null ) {
287+ routerServicePackage = sdlAppInfoList .get (0 ).getRouterServiceComponentName ().getPackageName ();
288+ }
289+ DebugTool .logInfo (TAG + ": This app's package: " + myPackage );
290+ DebugTool .logInfo (TAG + ": Router service app's package: " + routerServicePackage );
291+ if (myPackage != null && myPackage .equalsIgnoreCase (routerServicePackage )) {
292+ SdlDeviceListener sdlDeviceListener = getSdlDeviceListener (context , device );
293+ if (!sdlDeviceListener .isRunning ()) {
294+ sdlDeviceListener .start ();
295+ }
296+ } else {
297+ DebugTool .logInfo (TAG + ": Not the app to start the router service nor device listener" );
298+ }
299+ return ;
300+ }
301+ }
302+
237303 if (sdlAppInfoList != null && !sdlAppInfoList .isEmpty ()) {
238- serviceIntent = new Intent ();
239- serviceIntent .setComponent (sdlAppInfoList .get (0 ).getRouterServiceComponentName ());
304+ startRouterService (context , sdlAppInfoList .get (0 ).getRouterServiceComponentName (), altTransportWake , device );
240305 } else {
241306 Log .d (TAG , "No SDL Router Services found" );
242307 Log .d (TAG , "WARNING: This application has not specified its SdlRouterService correctly in the manifest. THIS WILL THROW AN EXCEPTION IN FUTURE RELEASES!!" );
243308 return ;
244309 }
245- if (altTransportWake ) {
246- serviceIntent .setAction (TransportConstants .BIND_REQUEST_TYPE_ALT_TRANSPORT );
247- }
248- if (device != null ){
249- serviceIntent .putExtra (BluetoothDevice .EXTRA_DEVICE , device );
250- }
251- try {
252- if (Build .VERSION .SDK_INT < Build .VERSION_CODES .O ) {
253- context .startService (serviceIntent );
254- }else {
255- serviceIntent .putExtra (FOREGROUND_EXTRA , true );
256- DebugTool .logInfo ("Attempting to startForegroundService - " + System .currentTimeMillis ());
257- setForegroundExceptionHandler (); //Prevent ANR in case the OS takes too long to start the service
258- context .startForegroundService (serviceIntent );
259310
311+ } else { //There are currently running services
312+ if (DebugTool .isDebugEnabled ()){
313+ for (ComponentName service : runningBluetoothServicePackage ){
314+ DebugTool .logInfo ("Currently running router service: " + service .getPackageName ());
260315 }
261- //Make sure to send this out for old apps to close down
262- SdlRouterService .LocalRouterService self = SdlRouterService .getLocalRouterService (serviceIntent , serviceIntent .getComponent ());
263- Intent restart = new Intent (SdlRouterService .REGISTER_NEWER_SERVER_INSTANCE_ACTION );
264- restart .putExtra (LOCAL_ROUTER_SERVICE_EXTRA , self );
265- restart .putExtra (LOCAL_ROUTER_SERVICE_DID_START_OWN , true );
266- context .sendBroadcast (restart );
267-
268- } catch (SecurityException e ) {
269- Log .e (TAG , "Security exception, process is bad" );
270316 }
271- } else {
272317 if (altTransportWake ) {
273318 wakeRouterServiceAltTransport (context );
274319 return ;
@@ -281,15 +326,19 @@ public void onComplete(Vector<ComponentName> routerServices) {
281326 }
282327 }
283328 });
284- return true ;
329+ return true ;
285330 }
286331
287332 private void wakeRouterServiceAltTransport (Context context ){
288333 Intent serviceIntent = new Intent ();
289334 serviceIntent .setAction (TransportConstants .BIND_REQUEST_TYPE_ALT_TRANSPORT );
290335 for (ComponentName compName : runningBluetoothServicePackage ) {
291336 serviceIntent .setComponent (compName );
292- context .startService (serviceIntent );
337+ try {
338+ context .startService (serviceIntent );
339+ } catch (Exception e ){
340+ DebugTool .logError ("Can't start router service for alt transport" );
341+ }
293342
294343 }
295344 }
@@ -329,10 +378,9 @@ public void uncaughtException(Thread t, Throwable e) {
329378 * Determines if an instance of the Router Service is currently running on the device.<p>
330379 * <b>Note:</b> This method no longer works on Android Oreo or newer
331380 * @param context A context to access Android system services through.
332- * @param pingService Set this to true if you want to make sure the service is up and listening to bluetooth
333381 * @return True if a SDL Router Service is currently running, false otherwise.
334382 */
335- private static boolean isRouterServiceRunning (Context context , boolean pingService ){
383+ private static boolean isRouterServiceRunning (Context context ){
336384 if (context == null ){
337385 Log .e (TAG , "Can't look for router service, context supplied was null" );
338386 return false ;
@@ -356,17 +404,15 @@ private static boolean isRouterServiceRunning(Context context, boolean pingServi
356404 //Log.d(TAG, "Found Service: "+ service.service.getClassName());
357405 if ((service .service .getClassName ()).toLowerCase (Locale .US ).contains (SDL_ROUTER_SERVICE_CLASS_NAME ) && AndroidTools .isServiceExported (context , service .service )) {
358406 runningBluetoothServicePackage .add (service .service ); //Store which instance is running
359- if (pingService ) {
360- pingRouterService (context , service .service .getPackageName (), service .service .getClassName ());
361- }
362407 }
363408 }
364409 return runningBluetoothServicePackage .size () > 0 ;
365410
366411 }
367412
368413 /**
369- * Attempts to ping a running router service
414+ * Attempts to ping a running router service. It does call startForegroundService so it is
415+ * important to only call this as a ping if the service is already started.
370416 * @param context A context to access Android system services through.
371417 * @param packageName Package name for service to ping
372418 * @param className Class name for service to ping
@@ -431,7 +477,7 @@ private static void requestTransportStatus(Context context, final SdlRouterStatu
431477 }
432478 return ;
433479 }
434- if ((!lookForServices || isRouterServiceRunning (context , false )) && !runningBluetoothServicePackage .isEmpty ()){ //So there is a service up, let's see if it's connected
480+ if ((!lookForServices || isRouterServiceRunning (context )) && !runningBluetoothServicePackage .isEmpty ()){ //So there is a service up, let's see if it's connected
435481 final ConcurrentLinkedQueue <ComponentName > list = new ConcurrentLinkedQueue <ComponentName >(runningBluetoothServicePackage );
436482 final SdlRouterStatusProvider .ConnectedStatusCallback sdlBrCallback = new SdlRouterStatusProvider .ConnectedStatusCallback () {
437483
@@ -471,12 +517,13 @@ public void onListObtained(boolean successful) {
471517 }else {
472518 Log .w (TAG , "Router service isn't running, returning false." );
473519 if (isBluetoothConnected ()){
474- Log .d (TAG , "Bluetooth is connected. Attempting to start Router Service" );
520+ Log .d (TAG , "Bluetooth is connected. Attempting to ping Router Service" );
475521 Intent serviceIntent = new Intent ();
476522 serviceIntent .setAction (TransportConstants .START_ROUTER_SERVICE_ACTION );
477523 serviceIntent .putExtra (TransportConstants .PING_ROUTER_SERVICE_EXTRA , true );
478- AndroidTools .sendExplicitBroadcast (context ,serviceIntent ,null );
524+ AndroidTools .sendExplicitBroadcast (context , serviceIntent ,null );
479525 }
526+
480527 if (callback !=null ){
481528 callback .onConnectionStatusUpdate (false , null ,context );
482529 }
@@ -500,6 +547,49 @@ private static boolean isBluetoothConnected() {
500547 return false ;
501548 }
502549
550+
551+ private static SdlDeviceListener getSdlDeviceListener (Context context , BluetoothDevice bluetoothDevice ){
552+
553+ synchronized (DEVICE_LISTENER_LOCK ){
554+ if (sdlDeviceListener == null ){
555+ sdlDeviceListener = new SdlDeviceListener (context , bluetoothDevice , new SdlDeviceListener .Callback () {
556+ @ Override
557+ public boolean onTransportConnected (Context context , BluetoothDevice bluetoothDevice ) {
558+
559+ synchronized (DEVICE_LISTENER_LOCK ){
560+ sdlDeviceListener = null ;
561+ if (context != null ) {
562+ final List <SdlAppInfo > sdlAppInfoList = AndroidTools .querySdlAppInfo (context , new SdlAppInfo .BestRouterComparator ());
563+ if (sdlAppInfoList != null && !sdlAppInfoList .isEmpty ()) {
564+ ComponentName routerService = sdlAppInfoList .get (0 ).getRouterServiceComponentName ();
565+ startRouterService (context , routerService , false , bluetoothDevice );
566+ }
567+ }
568+ }
569+
570+ return false ;
571+ }
572+
573+ @ Override
574+ public void onTransportDisconnected (BluetoothDevice bluetoothDevice ) {
575+ synchronized (DEVICE_LISTENER_LOCK ){
576+ sdlDeviceListener = null ;
577+ }
578+ }
579+
580+ @ Override
581+ public void onTransportError (BluetoothDevice bluetoothDevice ) {
582+ synchronized (DEVICE_LISTENER_LOCK ){
583+ sdlDeviceListener = null ;
584+ }
585+ }
586+ });
587+ }
588+ }
589+
590+ return sdlDeviceListener ;
591+ }
592+
503593 public static ComponentName consumeQueuedRouterService (){
504594 synchronized (QUEUED_SERVICE_LOCK ){
505595 ComponentName retVal = queuedService ;
0 commit comments