5252import com .smartdevicelink .R ;
5353import com .smartdevicelink .transport .RouterServiceValidator .TrustedListCallback ;
5454import com .smartdevicelink .transport .enums .TransportType ;
55+ import com .smartdevicelink .transport .utl .SdlDeviceListener ;
5556import com .smartdevicelink .util .AndroidTools ;
5657import com .smartdevicelink .util .DebugTool ;
5758import com .smartdevicelink .util .SdlAppInfo ;
@@ -84,6 +85,8 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver{
8485 private static final Object QUEUED_SERVICE_LOCK = new Object ();
8586 private static ComponentName queuedService = null ;
8687 private static Thread .UncaughtExceptionHandler foregroundExceptionHandler = null ;
88+ private static final Object DEVICE_LISTENER_LOCK = new Object ();
89+ private static SdlDeviceListener sdlDeviceListener ;
8790
8891 public int getRouterServiceVersion (){
8992 return SdlRouterService .ROUTER_SERVICE_VERSION_NUMBER ;
@@ -188,10 +191,7 @@ public void onListObtained(boolean successful) {
188191
189192 });
190193 }
191-
192- }else {
193- //This was previously not hooked up, so let's leave it commented out
194- //onSdlDisabled(context);
194+
195195 }
196196 return ;
197197 }else if (intent .getBooleanExtra (TransportConstants .PING_ROUTER_SERVICE_EXTRA , false )){
@@ -222,52 +222,101 @@ public void onListObtained(boolean successful) {
222222 }
223223 }
224224
225+ /**
226+ * This method will attempt to start the router service.
227+ * @param context to be used to start the service and send broadcasts
228+ * @param componentName the router service that should be started
229+ * @param altTransportWake if the alt transport flag should be set. Only used in debug
230+ * @param device the connected bluetooth device
231+ */
232+ private static void startRouterService (Context context , ComponentName componentName , boolean altTransportWake , BluetoothDevice device , boolean confirmedDevice ) {
233+ if (componentName == null ) {
234+ return ;
235+ }
236+
237+ Intent serviceIntent = new Intent ();
238+ serviceIntent .setComponent (componentName );
239+
240+ if (altTransportWake ) {
241+ serviceIntent .setAction (TransportConstants .BIND_REQUEST_TYPE_ALT_TRANSPORT );
242+ }
243+
244+ if (device != null ) {
245+ serviceIntent .putExtra (BluetoothDevice .EXTRA_DEVICE , device );
246+ }
247+
248+ if (confirmedDevice ) {
249+ serviceIntent .putExtra (TransportConstants .CONFIRMED_SDL_DEVICE , confirmedDevice );
250+ }
251+
252+ try {
253+ if (Build .VERSION .SDK_INT < Build .VERSION_CODES .O ) {
254+ context .startService (serviceIntent );
255+ } else {
256+ serviceIntent .putExtra (FOREGROUND_EXTRA , true );
257+ DebugTool .logInfo ("Attempting to startForegroundService - " + System .currentTimeMillis ());
258+ setForegroundExceptionHandler (); //Prevent ANR in case the OS takes too long to start the service
259+ context .startForegroundService (serviceIntent );
260+
261+ }
262+ //Make sure to send this out for old apps to close down
263+ SdlRouterService .LocalRouterService self = SdlRouterService .getLocalRouterService (serviceIntent , serviceIntent .getComponent ());
264+ Intent restart = new Intent (SdlRouterService .REGISTER_NEWER_SERVER_INSTANCE_ACTION );
265+ restart .putExtra (LOCAL_ROUTER_SERVICE_EXTRA , self );
266+ restart .putExtra (LOCAL_ROUTER_SERVICE_DID_START_OWN , true );
267+ context .sendBroadcast (restart );
268+
269+ } catch (SecurityException e ) {
270+ DebugTool .logError (TAG , "Security exception, process is bad" );
271+ }
272+ }
273+
225274 private boolean wakeUpRouterService (final Context context , final boolean ping , final boolean altTransportWake , final BluetoothDevice device ){
226- new ServiceFinder (context , context .getPackageName (), new ServiceFinder .ServiceFinderCallback () {
275+ new ServiceFinder (context , context .getPackageName (), new ServiceFinder .ServiceFinderCallback () {
227276 @ Override
228277 public void onComplete (Vector <ComponentName > routerServices ) {
229278 runningBluetoothServicePackage = new Vector <ComponentName >();
230279 runningBluetoothServicePackage .addAll (routerServices );
231280 if (runningBluetoothServicePackage .isEmpty ()) {
232281 //If there isn't a service running we should try to start one
233282 //We will try to sort the SDL enabled apps and find the one that's been installed the longest
234- Intent serviceIntent ;
235- List <SdlAppInfo > sdlAppInfoList = AndroidTools .querySdlAppInfo (context , new SdlAppInfo .BestRouterComparator ());
283+ final List <SdlAppInfo > sdlAppInfoList = AndroidTools .querySdlAppInfo (context , new SdlAppInfo .BestRouterComparator ());
284+ synchronized (DEVICE_LISTENER_LOCK ) {
285+ final boolean sdlDeviceListenerEnabled = SdlDeviceListener .isFeatureSupported (sdlAppInfoList );
286+ if (sdlDeviceListenerEnabled ) {
287+ String myPackage = context .getPackageName ();
288+ String routerServicePackage = null ;
289+ if (sdlAppInfoList != null && !sdlAppInfoList .isEmpty () && sdlAppInfoList .get (0 ).getRouterServiceComponentName () != null ) {
290+ routerServicePackage = sdlAppInfoList .get (0 ).getRouterServiceComponentName ().getPackageName ();
291+ }
292+ DebugTool .logInfo (TAG + ": This app's package: " + myPackage );
293+ DebugTool .logInfo (TAG + ": Router service app's package: " + routerServicePackage );
294+ if (myPackage != null && myPackage .equalsIgnoreCase (routerServicePackage )) {
295+ SdlDeviceListener sdlDeviceListener = getSdlDeviceListener (context , device );
296+ if (!sdlDeviceListener .isRunning ()) {
297+ sdlDeviceListener .start ();
298+ }
299+ } else {
300+ DebugTool .logInfo (TAG + ": Not the app to start the router service nor device listener" );
301+ }
302+ return ;
303+ }
304+ }
305+
236306 if (sdlAppInfoList != null && !sdlAppInfoList .isEmpty ()) {
237- serviceIntent = new Intent ();
238- serviceIntent .setComponent (sdlAppInfoList .get (0 ).getRouterServiceComponentName ());
307+ startRouterService (context , sdlAppInfoList .get (0 ).getRouterServiceComponentName (), altTransportWake , device , false );
239308 } else {
240- DebugTool .logInfo (TAG , "No SDL Router Services found" );
241- DebugTool .logInfo (TAG , "WARNING: This application has not specified its SdlRouterService correctly in the manifest. THIS WILL THROW AN EXCEPTION IN FUTURE RELEASES!!" );
309+ DebugTool .logInfo (TAG , "No SDL Router Services found" );
310+ DebugTool .logInfo (TAG , "WARNING: This application has not specified its SdlRouterService correctly in the manifest. THIS WILL THROW AN EXCEPTION IN FUTURE RELEASES!!" );
242311 return ;
243312 }
244- if (altTransportWake ) {
245- serviceIntent .setAction (TransportConstants .BIND_REQUEST_TYPE_ALT_TRANSPORT );
246- }
247- if (device != null ){
248- serviceIntent .putExtra (BluetoothDevice .EXTRA_DEVICE , device );
249- }
250- try {
251- if (Build .VERSION .SDK_INT < Build .VERSION_CODES .O ) {
252- context .startService (serviceIntent );
253- }else {
254- serviceIntent .putExtra (FOREGROUND_EXTRA , true );
255- DebugTool .logInfo (TAG ,"Attempting to startForegroundService - " + System .currentTimeMillis ());
256- setForegroundExceptionHandler (); //Prevent ANR in case the OS takes too long to start the service
257- context .startForegroundService (serviceIntent );
258313
314+ } else { //There are currently running services
315+ if (DebugTool .isDebugEnabled ()){
316+ for (ComponentName service : runningBluetoothServicePackage ){
317+ DebugTool .logInfo ("Currently running router service: " + service .getPackageName ());
259318 }
260- //Make sure to send this out for old apps to close down
261- SdlRouterService .LocalRouterService self = SdlRouterService .getLocalRouterService (serviceIntent , serviceIntent .getComponent ());
262- Intent restart = new Intent (SdlRouterService .REGISTER_NEWER_SERVER_INSTANCE_ACTION );
263- restart .putExtra (LOCAL_ROUTER_SERVICE_EXTRA , self );
264- restart .putExtra (LOCAL_ROUTER_SERVICE_DID_START_OWN , true );
265- context .sendBroadcast (restart );
266-
267- } catch (SecurityException e ) {
268- DebugTool .logError (TAG , "Security exception, process is bad" );
269319 }
270- } else {
271320 if (altTransportWake ) {
272321 wakeRouterServiceAltTransport (context );
273322 return ;
@@ -280,15 +329,19 @@ public void onComplete(Vector<ComponentName> routerServices) {
280329 }
281330 }
282331 });
283- return true ;
332+ return true ;
284333 }
285334
286335 private void wakeRouterServiceAltTransport (Context context ){
287336 Intent serviceIntent = new Intent ();
288337 serviceIntent .setAction (TransportConstants .BIND_REQUEST_TYPE_ALT_TRANSPORT );
289338 for (ComponentName compName : runningBluetoothServicePackage ) {
290339 serviceIntent .setComponent (compName );
291- context .startService (serviceIntent );
340+ try {
341+ context .startService (serviceIntent );
342+ } catch (Exception e ){
343+ DebugTool .logError (TAG , "Can't start router service for alt transport" );
344+ }
292345
293346 }
294347 }
@@ -328,10 +381,9 @@ public void uncaughtException(Thread t, Throwable e) {
328381 * Determines if an instance of the Router Service is currently running on the device.<p>
329382 * <b>Note:</b> This method no longer works on Android Oreo or newer
330383 * @param context A context to access Android system services through.
331- * @param pingService Set this to true if you want to make sure the service is up and listening to bluetooth
332384 * @return True if a SDL Router Service is currently running, false otherwise.
333385 */
334- private static boolean isRouterServiceRunning (Context context , boolean pingService ){
386+ private static boolean isRouterServiceRunning (Context context ){
335387 if (context == null ){
336388 DebugTool .logError (TAG , "Can't look for router service, context supplied was null" );
337389 return false ;
@@ -355,17 +407,15 @@ private static boolean isRouterServiceRunning(Context context, boolean pingServi
355407 //Log.d(TAG, "Found Service: "+ service.service.getClassName());
356408 if ((service .service .getClassName ()).toLowerCase (Locale .US ).contains (SDL_ROUTER_SERVICE_CLASS_NAME ) && AndroidTools .isServiceExported (context , service .service )) {
357409 runningBluetoothServicePackage .add (service .service ); //Store which instance is running
358- if (pingService ) {
359- pingRouterService (context , service .service .getPackageName (), service .service .getClassName ());
360- }
361410 }
362411 }
363412 return runningBluetoothServicePackage .size () > 0 ;
364413
365414 }
366415
367416 /**
368- * Attempts to ping a running router service
417+ * Attempts to ping a running router service. It does call startForegroundService so it is
418+ * important to only call this as a ping if the service is already started.
369419 * @param context A context to access Android system services through.
370420 * @param packageName Package name for service to ping
371421 * @param className Class name for service to ping
@@ -430,7 +480,7 @@ private static void requestTransportStatus(Context context, final SdlRouterStatu
430480 }
431481 return ;
432482 }
433- if ((!lookForServices || isRouterServiceRunning (context , false )) && !runningBluetoothServicePackage .isEmpty ()){ //So there is a service up, let's see if it's connected
483+ if ((!lookForServices || isRouterServiceRunning (context )) && !runningBluetoothServicePackage .isEmpty ()){ //So there is a service up, let's see if it's connected
434484 final ConcurrentLinkedQueue <ComponentName > list = new ConcurrentLinkedQueue <ComponentName >(runningBluetoothServicePackage );
435485 final SdlRouterStatusProvider .ConnectedStatusCallback sdlBrCallback = new SdlRouterStatusProvider .ConnectedStatusCallback () {
436486
@@ -470,12 +520,13 @@ public void onListObtained(boolean successful) {
470520 }else {
471521 DebugTool .logWarning (TAG , "Router service isn't running, returning false." );
472522 if (isBluetoothConnected ()){
473- DebugTool .logInfo (TAG , "Bluetooth is connected. Attempting to start Router Service" );
523+ DebugTool .logInfo (TAG , "Bluetooth is connected. Attempting to ping Router Service" );
474524 Intent serviceIntent = new Intent ();
475525 serviceIntent .setAction (TransportConstants .START_ROUTER_SERVICE_ACTION );
476526 serviceIntent .putExtra (TransportConstants .PING_ROUTER_SERVICE_EXTRA , true );
477- AndroidTools .sendExplicitBroadcast (context ,serviceIntent ,null );
527+ AndroidTools .sendExplicitBroadcast (context , serviceIntent ,null );
478528 }
529+
479530 if (callback !=null ){
480531 callback .onConnectionStatusUpdate (false , null ,context );
481532 }
@@ -499,6 +550,49 @@ private static boolean isBluetoothConnected() {
499550 return false ;
500551 }
501552
553+
554+ private static SdlDeviceListener getSdlDeviceListener (Context context , BluetoothDevice bluetoothDevice ){
555+
556+ synchronized (DEVICE_LISTENER_LOCK ){
557+ if (sdlDeviceListener == null ){
558+ sdlDeviceListener = new SdlDeviceListener (context , bluetoothDevice , new SdlDeviceListener .Callback () {
559+ @ Override
560+ public boolean onTransportConnected (Context context , BluetoothDevice bluetoothDevice ) {
561+
562+ synchronized (DEVICE_LISTENER_LOCK ){
563+ sdlDeviceListener = null ;
564+ if (context != null ) {
565+ final List <SdlAppInfo > sdlAppInfoList = AndroidTools .querySdlAppInfo (context , new SdlAppInfo .BestRouterComparator ());
566+ if (sdlAppInfoList != null && !sdlAppInfoList .isEmpty ()) {
567+ ComponentName routerService = sdlAppInfoList .get (0 ).getRouterServiceComponentName ();
568+ startRouterService (context , routerService , false , bluetoothDevice , true );
569+ }
570+ }
571+ }
572+
573+ return false ;
574+ }
575+
576+ @ Override
577+ public void onTransportDisconnected (BluetoothDevice bluetoothDevice ) {
578+ synchronized (DEVICE_LISTENER_LOCK ){
579+ sdlDeviceListener = null ;
580+ }
581+ }
582+
583+ @ Override
584+ public void onTransportError (BluetoothDevice bluetoothDevice ) {
585+ synchronized (DEVICE_LISTENER_LOCK ){
586+ sdlDeviceListener = null ;
587+ }
588+ }
589+ });
590+ }
591+ }
592+
593+ return sdlDeviceListener ;
594+ }
595+
502596 public static ComponentName consumeQueuedRouterService (){
503597 synchronized (QUEUED_SERVICE_LOCK ){
504598 ComponentName retVal = queuedService ;
0 commit comments