Skip to content

Commit 7306e2b

Browse files
committed
Implement SdlDeviceListener
1 parent 1aa070b commit 7306e2b

2 files changed

Lines changed: 145 additions & 44 deletions

File tree

android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java

Lines changed: 133 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import com.smartdevicelink.R;
5454
import com.smartdevicelink.transport.RouterServiceValidator.TrustedListCallback;
5555
import com.smartdevicelink.transport.enums.TransportType;
56+
import com.smartdevicelink.transport.utl.SdlDeviceListener;
5657
import com.smartdevicelink.util.AndroidTools;
5758
import com.smartdevicelink.util.DebugTool;
5859
import 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;

android/sdl_android/src/main/java/com/smartdevicelink/transport/TransportManager.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import com.smartdevicelink.protocol.SdlPacket;
5050
import com.smartdevicelink.protocol.enums.ControlFrameTags;
5151
import com.smartdevicelink.transport.enums.TransportType;
52+
import com.smartdevicelink.transport.utl.SdlDeviceListener;
5253
import com.smartdevicelink.transport.utl.TransportRecord;
5354
import com.smartdevicelink.util.DebugTool;
5455

@@ -100,7 +101,7 @@ public void onFinishedValidation(boolean valid, ComponentName name) {
100101
if (valid) {
101102
mConfig.service = name;
102103
transport = new TransportBrokerImpl(contextWeakReference.get(), mConfig.appId, mConfig.service);
103-
DebugTool.logInfo("TransportManager start got called; transport=" + transport);
104+
DebugTool.logInfo("TransportManager start was called; transport = " + transport);
104105
if(transport != null){
105106
transport.start();
106107
}
@@ -302,6 +303,16 @@ public synchronized boolean onHardwareConnected(List<TransportRecord> transports
302303
transportStatus.clear();
303304
transportStatus.addAll(transports);
304305
}
306+
//If a bluetooth device has connected, make sure to save the mac address in the case
307+
//this app is asked to host the router service, the app knows to do so immediately on connection.
308+
if(transports != null && transports.size() > 0) {
309+
for (TransportRecord record : transports) {
310+
if(record != null && TransportType.BLUETOOTH.equals(record.getType())) {
311+
SdlDeviceListener.setSDLConnectedStatus(contextWeakReference.get(), record.getAddress(),true);
312+
}
313+
}
314+
}
315+
305316
transportListener.onTransportConnected(transports);
306317
return true;
307318
}

0 commit comments

Comments
 (0)