From 3b2f02bcc381fb6079623e41951bbd75958c1072 Mon Sep 17 00:00:00 2001 From: RHenigan Date: Mon, 14 Feb 2022 15:52:44 -0500 Subject: Clean up and comments --- .../java/com/sdl/hellosdlandroid/SdlReceiver.java | 3 ++ .../transport/SdlBroadcastReceiver.java | 39 ++++++++++++++-------- .../transport/SdlRouterService.java | 18 ++++++---- .../com/smartdevicelink/util/AndroidTools.java | 1 - .../smartdevicelink/util/IntegrationValidator.java | 2 -- 5 files changed, 41 insertions(+), 22 deletions(-) (limited to 'android') diff --git a/android/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlReceiver.java b/android/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlReceiver.java index 758906190..2690d153f 100755 --- a/android/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlReceiver.java +++ b/android/hello_sdl_android/src/main/java/com/sdl/hellosdlandroid/SdlReceiver.java @@ -18,6 +18,9 @@ public class SdlReceiver extends SdlBroadcastReceiver { DebugTool.logInfo(TAG, "SDL Enabled"); intent.setClass(context, SdlService.class); + // Starting with Android S SdlService needs to be started from a foreground context. + // We will check the intent for a pendingIntent parcelable extra + // This pendingIntent allows us to start the SdlService from the context of the active router service which is in the foreground if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (intent.getParcelableExtra(TransportConstants.PENDING_INTENT_EXTRA) != null) { PendingIntent pendingIntent = (PendingIntent) intent.getParcelableExtra(TransportConstants.PENDING_INTENT_EXTRA); 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 51e59675e..4bea676b8 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 @@ -73,6 +73,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"; @@ -302,15 +303,17 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { boolean preAndroid12RouterServiceOnDevice = false; for (SdlAppInfo appInfo : sdlAppInfoList) { - //If the RS version is older than Android 12 update version - if (appInfo.getRouterServiceVersion() < 16) { + //If an installed app RS version is older than Android 12 update version (16) + if (appInfo.getRouterServiceVersion() < ANDROID_12_ROUTER_SERVICE_VERSION) { preAndroid12RouterServiceOnDevice = true; break; } } + // 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 (!preAndroid12RouterServiceOnDevice && !AndroidTools.isBtConnectPermissionGranted(context, routerServicePackage) && sdlAppInfoList.size() > 1) { for (SdlAppInfo appInfo : sdlAppInfoList) { if (AndroidTools.isBtConnectPermissionGranted(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; } @@ -383,13 +386,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(); @@ -618,21 +624,21 @@ public abstract class SdlBroadcastReceiver extends BroadcastReceiver { final List sdlAppInfoList = AndroidTools.querySdlAppInfo(context, new SdlAppInfo.BestRouterComparator(), vehicleType); if (sdlAppInfoList != null && !sdlAppInfoList.isEmpty()) { ComponentName routerService = sdlAppInfoList.get(0).getRouterServiceComponentName(); - //If we are on android 12 check the app has BT permissions - //If it does not try to find another app in the list that does; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { boolean preAndroid12RouterServiceOnDevice = false; for (SdlAppInfo appInfo : sdlAppInfoList) { - //If the RS version is older than Android 12 update version - if (appInfo.getRouterServiceVersion() < 16) { + //If an installed app RS version is older than Android 12 update version (16) + if (appInfo.getRouterServiceVersion() < ANDROID_12_ROUTER_SERVICE_VERSION) { preAndroid12RouterServiceOnDevice = true; break; } } + // 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 (!preAndroid12RouterServiceOnDevice && !AndroidTools.isBtConnectPermissionGranted(context, routerService.getPackageName()) && sdlAppInfoList.size() > 1) { for (SdlAppInfo appInfo : sdlAppInfoList) { if (AndroidTools.isBtConnectPermissionGranted(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; } } @@ -696,6 +702,13 @@ 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"; } diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java index aa16b9af9..970e818ee 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java @@ -372,6 +372,7 @@ public class SdlRouterService extends Service { switch (msg.what) { case TransportConstants.ROUTER_REQUEST_BT_CLIENT_CONNECT: + //Starting with Android 12 this use case will require the BLUETOOTH_SCAN PERMISSION if (!AndroidTools.isBtScanPermissionGranted(service.getApplicationContext(), service.getPackageName())) { break; } @@ -1106,9 +1107,9 @@ public class SdlRouterService extends Service { return false; } - // If Android 12 or newer make sure we have BT Runtime permissions + // If Android 12 or newer make sure we have BLUETOOTH_CONNECT Runtime permission if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !AndroidTools.isBtConnectPermissionGranted(this, this.getPackageName())) { - if (!isConnectedOverUSB) { + if (!isConnectedOverUSB) { //If BLUETOOTH_CONNECT permission is not granted We want to make sure we are connected over USB return false; } } @@ -1142,6 +1143,7 @@ public class SdlRouterService extends Service { return true; } + @Override public void onCreate() { super.onCreate(); @@ -1176,7 +1178,6 @@ public class SdlRouterService extends Service { if (info.getRouterServiceComponentName().equals(name) && listSize > i + 1) { SdlAppInfo nextUp = sdlAppInfoList.get(i + 1); Intent serviceIntent = new Intent(); - //Add check if it is second pass also add extra serviceIntent.setComponent(nextUp.getRouterServiceComponentName()); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { startService(serviceIntent); @@ -1195,7 +1196,6 @@ public class SdlRouterService extends Service { DebugTool.logInfo(TAG, "No sdl apps found"); return; } - closing = true; closeBluetoothSerialServer(); notifyAltTransportOfClose(TransportConstants.ROUTER_SHUTTING_DOWN_REASON_NEWER_SERVICE); @@ -1785,6 +1785,7 @@ public class SdlRouterService extends Service { private synchronized void initBluetoothSerialService() { if (waitingForBTRuntimePermissions) { + //The app has not be granted the BLUETOOTH_CONNECT runtime permission return; } @@ -1845,6 +1846,11 @@ public class SdlRouterService extends Service { startService.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + //Starting in Android 12 we need to start services from a foreground context + //To enable developers to be able to start their SdlService from the "background" + //we will attach a pendingIntent as an extra to the intent + //the developer can use this pendingIntent to start their SdlService from the context of + //the active RouterService Intent pending = new Intent(); PendingIntent pendingIntent = PendingIntent.getForegroundService(this, (int) System.currentTimeMillis(), pending, PendingIntent.FLAG_MUTABLE | Intent.FILL_IN_COMPONENT); startService.putExtra(TransportConstants.PENDING_INTENT_EXTRA, pendingIntent); @@ -1859,10 +1865,10 @@ public class SdlRouterService extends Service { } if (isConnectedOverUSB && !AndroidTools.isBtConnectPermissionGranted(SdlRouterService.this, SdlRouterService.this.getPackageName())) { - //Delay starting bluetoothTransport + //Delay starting bluetoothTransport when we are connected over USB and the app does not have the BLUETOOTH_CONNECT permissions waitingForBTRuntimePermissions = true; btPermissionsHandler = new Handler(Looper.myLooper()); - //Continuously Check for the Bluetooth Permissions + //Continuously Check for the BLUETOOTH_CONNECT Permission btPermissionsRunnable = new Runnable() { @Override public void run() { diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java b/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java index 3e5665556..e8f88c259 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java @@ -32,7 +32,6 @@ package com.smartdevicelink.util; -import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java b/android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java index 930436729..8e904a45f 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/util/IntegrationValidator.java @@ -33,14 +33,12 @@ package com.smartdevicelink.util; import android.Manifest; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; import android.os.Build; import com.smartdevicelink.R; -- cgit v1.2.1