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,101 @@ 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 , boolean confirmedDevice ) {
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+ if (confirmedDevice ) {
250+ serviceIntent .putExtra (TransportConstants .CONFIRMED_SDL_DEVICE , confirmedDevice );
251+ }
252+
253+ try {
254+ if (Build .VERSION .SDK_INT < Build .VERSION_CODES .O ) {
255+ context .startService (serviceIntent );
256+ } else {
257+ serviceIntent .putExtra (FOREGROUND_EXTRA , true );
258+ DebugTool .logInfo ("Attempting to startForegroundService - " + System .currentTimeMillis ());
259+ setForegroundExceptionHandler (); //Prevent ANR in case the OS takes too long to start the service
260+ context .startForegroundService (serviceIntent );
261+
262+ }
263+ //Make sure to send this out for old apps to close down
264+ SdlRouterService .LocalRouterService self = SdlRouterService .getLocalRouterService (serviceIntent , serviceIntent .getComponent ());
265+ Intent restart = new Intent (SdlRouterService .REGISTER_NEWER_SERVER_INSTANCE_ACTION );
266+ restart .putExtra (LOCAL_ROUTER_SERVICE_EXTRA , self );
267+ restart .putExtra (LOCAL_ROUTER_SERVICE_DID_START_OWN , true );
268+ context .sendBroadcast (restart );
269+
270+ } catch (SecurityException e ) {
271+ Log .e (TAG , "Security exception, process is bad" );
272+ }
273+ }
274+
226275 private boolean wakeUpRouterService (final Context context , final boolean ping , final boolean altTransportWake , final BluetoothDevice device ){
227- new ServiceFinder (context , context .getPackageName (), new ServiceFinder .ServiceFinderCallback () {
276+ new ServiceFinder (context , context .getPackageName (), new ServiceFinder .ServiceFinderCallback () {
228277 @ Override
229278 public void onComplete (Vector <ComponentName > routerServices ) {
230279 runningBluetoothServicePackage = new Vector <ComponentName >();
231280 runningBluetoothServicePackage .addAll (routerServices );
232281 if (runningBluetoothServicePackage .isEmpty ()) {
233282 //If there isn't a service running we should try to start one
234283 //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 ());
284+ final List <SdlAppInfo > sdlAppInfoList = AndroidTools .querySdlAppInfo (context , new SdlAppInfo .BestRouterComparator ());
285+ synchronized (DEVICE_LISTENER_LOCK ) {
286+ final boolean sdlDeviceListenerEnabled = SdlDeviceListener .isFeatureSupported (sdlAppInfoList );
287+ if (sdlDeviceListenerEnabled ) {
288+ String myPackage = context .getPackageName ();
289+ String routerServicePackage = null ;
290+ if (sdlAppInfoList != null && !sdlAppInfoList .isEmpty () && sdlAppInfoList .get (0 ).getRouterServiceComponentName () != null ) {
291+ routerServicePackage = sdlAppInfoList .get (0 ).getRouterServiceComponentName ().getPackageName ();
292+ }
293+ DebugTool .logInfo (TAG + ": This app's package: " + myPackage );
294+ DebugTool .logInfo (TAG + ": Router service app's package: " + routerServicePackage );
295+ if (myPackage != null && myPackage .equalsIgnoreCase (routerServicePackage )) {
296+ SdlDeviceListener sdlDeviceListener = getSdlDeviceListener (context , device );
297+ if (!sdlDeviceListener .isRunning ()) {
298+ sdlDeviceListener .start ();
299+ }
300+ } else {
301+ DebugTool .logInfo (TAG + ": Not the app to start the router service nor device listener" );
302+ }
303+ return ;
304+ }
305+ }
306+
237307 if (sdlAppInfoList != null && !sdlAppInfoList .isEmpty ()) {
238- serviceIntent = new Intent ();
239- serviceIntent .setComponent (sdlAppInfoList .get (0 ).getRouterServiceComponentName ());
308+ startRouterService (context , sdlAppInfoList .get (0 ).getRouterServiceComponentName (), altTransportWake , device , false );
240309 } else {
241310 Log .d (TAG , "No SDL Router Services found" );
242311 Log .d (TAG , "WARNING: This application has not specified its SdlRouterService correctly in the manifest. THIS WILL THROW AN EXCEPTION IN FUTURE RELEASES!!" );
243312 return ;
244313 }
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 );
259314
315+ } else { //There are currently running services
316+ if (DebugTool .isDebugEnabled ()){
317+ for (ComponentName service : runningBluetoothServicePackage ){
318+ DebugTool .logInfo ("Currently running router service: " + service .getPackageName ());
260319 }
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" );
270320 }
271- } else {
272321 if (altTransportWake ) {
273322 wakeRouterServiceAltTransport (context );
274323 return ;
@@ -281,15 +330,19 @@ public void onComplete(Vector<ComponentName> routerServices) {
281330 }
282331 }
283332 });
284- return true ;
333+ return true ;
285334 }
286335
287336 private void wakeRouterServiceAltTransport (Context context ){
288337 Intent serviceIntent = new Intent ();
289338 serviceIntent .setAction (TransportConstants .BIND_REQUEST_TYPE_ALT_TRANSPORT );
290339 for (ComponentName compName : runningBluetoothServicePackage ) {
291340 serviceIntent .setComponent (compName );
292- context .startService (serviceIntent );
341+ try {
342+ context .startService (serviceIntent );
343+ } catch (Exception e ){
344+ DebugTool .logError ("Can't start router service for alt transport" );
345+ }
293346
294347 }
295348 }
@@ -329,10 +382,9 @@ public void uncaughtException(Thread t, Throwable e) {
329382 * Determines if an instance of the Router Service is currently running on the device.<p>
330383 * <b>Note:</b> This method no longer works on Android Oreo or newer
331384 * @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
333385 * @return True if a SDL Router Service is currently running, false otherwise.
334386 */
335- private static boolean isRouterServiceRunning (Context context , boolean pingService ){
387+ private static boolean isRouterServiceRunning (Context context ){
336388 if (context == null ){
337389 Log .e (TAG , "Can't look for router service, context supplied was null" );
338390 return false ;
@@ -356,17 +408,15 @@ private static boolean isRouterServiceRunning(Context context, boolean pingServi
356408 //Log.d(TAG, "Found Service: "+ service.service.getClassName());
357409 if ((service .service .getClassName ()).toLowerCase (Locale .US ).contains (SDL_ROUTER_SERVICE_CLASS_NAME ) && AndroidTools .isServiceExported (context , service .service )) {
358410 runningBluetoothServicePackage .add (service .service ); //Store which instance is running
359- if (pingService ) {
360- pingRouterService (context , service .service .getPackageName (), service .service .getClassName ());
361- }
362411 }
363412 }
364413 return runningBluetoothServicePackage .size () > 0 ;
365414
366415 }
367416
368417 /**
369- * Attempts to ping a running router service
418+ * Attempts to ping a running router service. It does call startForegroundService so it is
419+ * important to only call this as a ping if the service is already started.
370420 * @param context A context to access Android system services through.
371421 * @param packageName Package name for service to ping
372422 * @param className Class name for service to ping
@@ -431,7 +481,7 @@ private static void requestTransportStatus(Context context, final SdlRouterStatu
431481 }
432482 return ;
433483 }
434- if ((!lookForServices || isRouterServiceRunning (context , false )) && !runningBluetoothServicePackage .isEmpty ()){ //So there is a service up, let's see if it's connected
484+ if ((!lookForServices || isRouterServiceRunning (context )) && !runningBluetoothServicePackage .isEmpty ()){ //So there is a service up, let's see if it's connected
435485 final ConcurrentLinkedQueue <ComponentName > list = new ConcurrentLinkedQueue <ComponentName >(runningBluetoothServicePackage );
436486 final SdlRouterStatusProvider .ConnectedStatusCallback sdlBrCallback = new SdlRouterStatusProvider .ConnectedStatusCallback () {
437487
@@ -471,12 +521,13 @@ public void onListObtained(boolean successful) {
471521 }else {
472522 Log .w (TAG , "Router service isn't running, returning false." );
473523 if (isBluetoothConnected ()){
474- Log .d (TAG , "Bluetooth is connected. Attempting to start Router Service" );
524+ Log .d (TAG , "Bluetooth is connected. Attempting to ping Router Service" );
475525 Intent serviceIntent = new Intent ();
476526 serviceIntent .setAction (TransportConstants .START_ROUTER_SERVICE_ACTION );
477527 serviceIntent .putExtra (TransportConstants .PING_ROUTER_SERVICE_EXTRA , true );
478- AndroidTools .sendExplicitBroadcast (context ,serviceIntent ,null );
528+ AndroidTools .sendExplicitBroadcast (context , serviceIntent ,null );
479529 }
530+
480531 if (callback !=null ){
481532 callback .onConnectionStatusUpdate (false , null ,context );
482533 }
@@ -500,6 +551,49 @@ private static boolean isBluetoothConnected() {
500551 return false ;
501552 }
502553
554+
555+ private static SdlDeviceListener getSdlDeviceListener (Context context , BluetoothDevice bluetoothDevice ){
556+
557+ synchronized (DEVICE_LISTENER_LOCK ){
558+ if (sdlDeviceListener == null ){
559+ sdlDeviceListener = new SdlDeviceListener (context , bluetoothDevice , new SdlDeviceListener .Callback () {
560+ @ Override
561+ public boolean onTransportConnected (Context context , BluetoothDevice bluetoothDevice ) {
562+
563+ synchronized (DEVICE_LISTENER_LOCK ){
564+ sdlDeviceListener = null ;
565+ if (context != null ) {
566+ final List <SdlAppInfo > sdlAppInfoList = AndroidTools .querySdlAppInfo (context , new SdlAppInfo .BestRouterComparator ());
567+ if (sdlAppInfoList != null && !sdlAppInfoList .isEmpty ()) {
568+ ComponentName routerService = sdlAppInfoList .get (0 ).getRouterServiceComponentName ();
569+ startRouterService (context , routerService , false , bluetoothDevice , true );
570+ }
571+ }
572+ }
573+
574+ return false ;
575+ }
576+
577+ @ Override
578+ public void onTransportDisconnected (BluetoothDevice bluetoothDevice ) {
579+ synchronized (DEVICE_LISTENER_LOCK ){
580+ sdlDeviceListener = null ;
581+ }
582+ }
583+
584+ @ Override
585+ public void onTransportError (BluetoothDevice bluetoothDevice ) {
586+ synchronized (DEVICE_LISTENER_LOCK ){
587+ sdlDeviceListener = null ;
588+ }
589+ }
590+ });
591+ }
592+ }
593+
594+ return sdlDeviceListener ;
595+ }
596+
503597 public static ComponentName consumeQueuedRouterService (){
504598 synchronized (QUEUED_SERVICE_LOCK ){
505599 ComponentName retVal = queuedService ;
0 commit comments