diff options
Diffstat (limited to 'android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java')
-rw-r--r-- | android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java | 74 |
1 files changed, 64 insertions, 10 deletions
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java index 93f6cc850..7bed1b482 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlBroadcastReceiver.java @@ -66,6 +66,7 @@ import java.util.Locale; import java.util.Vector; import java.util.concurrent.ConcurrentLinkedQueue; +import static android.Manifest.permission.BLUETOOTH_CONNECT; import static com.smartdevicelink.transport.TransportConstants.FOREGROUND_EXTRA; public abstract class SdlBroadcastReceiver extends BroadcastReceiver { @@ -73,6 +74,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver { private static final String TAG = "Sdl Broadcast Receiver"; protected static final String SDL_ROUTER_SERVICE_CLASS_NAME = "sdlrouterservice"; + protected static final int ANDROID_12_ROUTER_SERVICE_VERSION = 16; public static final String LOCAL_ROUTER_SERVICE_EXTRA = "router_service"; public static final String LOCAL_ROUTER_SERVICE_DID_START_OWN = "did_start"; @@ -90,6 +92,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver { private static Thread.UncaughtExceptionHandler foregroundExceptionHandler = null; private static final Object DEVICE_LISTENER_LOCK = new Object(); private static SdlDeviceListener sdlDeviceListener; + private static String serviceName = null; public int getRouterServiceVersion() { return SdlRouterService.ROUTER_SERVICE_VERSION_NUMBER; @@ -98,6 +101,7 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver { @Override @CallSuper public void onReceive(Context context, Intent intent) { + //Log.i(TAG, "Sdl Receiver Activated"); final String action = intent.getAction(); if (action == null) { @@ -132,6 +136,10 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver { device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); } + if (serviceName == null) { + serviceName = getSdlServiceName(); + } + boolean didStart = false; if (localRouterClass == null) { localRouterClass = defineLocalSdlRouterClass(); @@ -296,6 +304,18 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver { String routerServicePackage = null; if (sdlAppInfoList != null && !sdlAppInfoList.isEmpty() && sdlAppInfoList.get(0).getRouterServiceComponentName() != null) { routerServicePackage = sdlAppInfoList.get(0).getRouterServiceComponentName().getPackageName(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + // If all apps have a RS newer than the Android 12 update, chosen app does not have BT Connect permissions, and more than 1 sdl app is installed + if (!isPreAndroid12RSOnDevice(sdlAppInfoList) && !AndroidTools.isPermissionGranted(BLUETOOTH_CONNECT, context, routerServicePackage) && sdlAppInfoList.size() > 1) { + for (SdlAppInfo appInfo : sdlAppInfoList) { + if (AndroidTools.isPermissionGranted(BLUETOOTH_CONNECT, context, appInfo.getRouterServiceComponentName().getPackageName())) { + //If this app in the list has BT Connect permissions, we want to use that apps RS + routerServicePackage = appInfo.getRouterServiceComponentName().getPackageName(); + break; + } + } + } + } } DebugTool.logInfo(TAG, ": This app's package: " + myPackage); DebugTool.logInfo(TAG, ": Router service app's package: " + routerServicePackage); @@ -362,13 +382,16 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver { } /** - * This method will set a new UncaughtExceptionHandler for the current thread. The only - * purpose of the custom UncaughtExceptionHandler is to catch the rare occurrence that the - * SdlRouterService can't be started fast enough by the system after calling - * startForegroundService so the onCreate method doesn't get called before the foreground promise - * timer expires. The new UncaughtExceptionHandler will catch that specific exception and tell the - * main looper to continue forward. This still leaves the SdlRouterService killed, but prevents - * an ANR to the app that makes the startForegroundService call. + * This method will set a new UncaughtExceptionHandler for the current thread. + * There are two exceptions we want to catch here. The first exception is the rare + * occurrence that the SdlRouterService can't be started fast enough by the system after calling + * startForegroundService so the onCreate method doesn't get called before the foreground + * promise timer expires. The second is for the instance where the developers "SdlService" class + * can't be started fast enough by the system after calling startForegroundService OR the app + * is unable to start the "SdlService" class because the developer did not export the service + * in the manifest. The new UncaughtExceptionHandler will catch these specific exception and + * tell the main looper to continue forward. This still leaves the respective Service killed, + * but prevents an ANR to the app that makes the startForegroundService call. */ static protected void setForegroundExceptionHandler() { final Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); @@ -378,10 +401,9 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver { public void uncaughtException(Thread t, Throwable e) { if (e != null && e instanceof AndroidRuntimeException - && "android.app.RemoteServiceException".equals(e.getClass().getName()) //android.app.RemoteServiceException is a private class + && ("android.app.RemoteServiceException".equals(e.getClass().getName()) || "android.app.ForegroundServiceDidNotStartInTimeException".equals(e.getClass().getName())) //android.app.RemoteServiceException is a private class && e.getMessage() != null - && e.getMessage().contains("SdlRouterService")) { - + && (e.getMessage().contains("SdlRouterService")) || e.getMessage().contains(serviceName)) { DebugTool.logInfo(TAG, "Handling failed startForegroundService call"); Looper.loop(); } else if (defaultUncaughtExceptionHandler != null) { //No other exception should be handled @@ -598,6 +620,18 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver { final List<SdlAppInfo> sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator(), vehicleType); if (sdlAppInfoList != null && !sdlAppInfoList.isEmpty()) { ComponentName routerService = sdlAppInfoList.get(0).getRouterServiceComponentName(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + // If all apps have a RS newer than the Android 12 update, chosen app does not have BT Connect permissions, and more than 1 sdl app is installed + if (!isPreAndroid12RSOnDevice(sdlAppInfoList) && !AndroidTools.isPermissionGranted(BLUETOOTH_CONNECT, context, routerService.getPackageName()) && sdlAppInfoList.size() > 1) { + for (SdlAppInfo appInfo : sdlAppInfoList) { + if (AndroidTools.isPermissionGranted(BLUETOOTH_CONNECT, context, appInfo.getRouterServiceComponentName().getPackageName())) { + routerService = appInfo.getRouterServiceComponentName(); + //If this app in the list has BT Connect permissions, we want to use that apps RS + break; + } + } + } + } startRouterService(context, routerService, false, bluetoothDevice, true, vehicleType); } } @@ -634,6 +668,16 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver { } } + private static boolean isPreAndroid12RSOnDevice(List<SdlAppInfo> sdlAppInfoList) { + for (SdlAppInfo appInfo : sdlAppInfoList) { + //If an installed app RS version is older than Android 12 update version (16) + if (appInfo.getRouterServiceVersion() < ANDROID_12_ROUTER_SERVICE_VERSION) { + return true; + } + } + return false; + } + /** * We need to define this for local copy of the Sdl Router Service class. * It will be the main point of connection for Sdl enabled apps @@ -656,6 +700,16 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver { */ public abstract void onSdlEnabled(Context context, Intent intent); + + /** + * The developer can override this method to return the name of the class that manages their + * SdlService. This method is used to ensure the SdlBroadcastReceivers exception catcher catches + * the correct exception that may be thrown by the app trying to start their SdlService. If this + * exception is not caught the user may experience an ANR for that app. + */ + public String getSdlServiceName() { + return "SdlService"; + } //public abstract void onSdlDisabled(Context context); //Removing for now until we're able to abstract from developer |