|
70 | 70 | import android.os.ParcelFileDescriptor; |
71 | 71 | import android.os.Parcelable; |
72 | 72 | import android.os.RemoteException; |
| 73 | +import android.provider.Settings; |
73 | 74 | import android.util.AndroidRuntimeException; |
74 | 75 | import android.util.SparseArray; |
75 | 76 | import android.util.SparseIntArray; |
@@ -217,6 +218,10 @@ public class SdlRouterService extends Service { |
217 | 218 | private boolean startSequenceComplete = false; |
218 | 219 | private VehicleType receivedVehicleType; |
219 | 220 | private boolean isConnectedOverUSB; |
| 221 | + private boolean waitingForBTRuntimePermissions = false; |
| 222 | + private Handler btPermissionsHandler; |
| 223 | + private Runnable btPermissionsRunnable; |
| 224 | + private final static int BT_PERMISSIONS_CHECK_FREQUENCY = 1000; |
220 | 225 |
|
221 | 226 | private ExecutorService packetExecutor = null; |
222 | 227 | ConcurrentHashMap<TransportType, PacketWriteTaskMaster> packetWriteTaskMasterMap = null; |
@@ -1098,11 +1103,27 @@ private boolean initCheck() { |
1098 | 1103 | return false; |
1099 | 1104 | } |
1100 | 1105 |
|
1101 | | - //If Android 12 or newer make sure we have BT Runtime permissions |
1102 | | - boolean supportsBTPermissions = AndroidTools.areBtPermissionsGranted(this, this.getPackageName()); |
1103 | | - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !supportsBTPermissions) { |
1104 | | - DebugTool.logError(TAG, "Bluetooth Runtime Permissions are not granted. Shutting down"); |
1105 | | - return false; |
| 1106 | + // If Android 12 or newer make sure we have BT Runtime permissions |
| 1107 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !AndroidTools.areBtPermissionsGranted(this, this.getPackageName())) { |
| 1108 | + if (isConnectedOverUSB) { |
| 1109 | + waitingForBTRuntimePermissions = true; |
| 1110 | + btPermissionsHandler = new Handler(Looper.myLooper()); |
| 1111 | + btPermissionsRunnable = new Runnable() { |
| 1112 | + @Override |
| 1113 | + public void run() { |
| 1114 | + if (!AndroidTools.areBtPermissionsGranted(SdlRouterService.this, SdlRouterService.this.getPackageName())) { |
| 1115 | + btPermissionsHandler.postDelayed(btPermissionsRunnable, BT_PERMISSIONS_CHECK_FREQUENCY); |
| 1116 | + } else { |
| 1117 | + waitingForBTRuntimePermissions = false; |
| 1118 | + initBluetoothSerialService(); |
| 1119 | + } |
| 1120 | + } |
| 1121 | + }; |
| 1122 | + btPermissionsHandler.postDelayed(btPermissionsRunnable, BT_PERMISSIONS_CHECK_FREQUENCY); |
| 1123 | + showBTPermissionsNotification(); |
| 1124 | + } else { |
| 1125 | + return false; |
| 1126 | + } |
1106 | 1127 | } |
1107 | 1128 |
|
1108 | 1129 | if (!AndroidTools.isServiceExported(this, new ComponentName(this, this.getClass()))) { //We want to check to see if our service is actually exported |
@@ -1776,6 +1797,10 @@ public void closeSelf() { |
1776 | 1797 | } |
1777 | 1798 |
|
1778 | 1799 | private synchronized void initBluetoothSerialService() { |
| 1800 | + if (waitingForBTRuntimePermissions) { |
| 1801 | + return; |
| 1802 | + } |
| 1803 | + |
1779 | 1804 | if (legacyModeEnabled) { |
1780 | 1805 | DebugTool.logInfo(TAG, "Not starting own bluetooth during legacy mode"); |
1781 | 1806 | return; |
@@ -3885,4 +3910,59 @@ private void notifySppError() { |
3885 | 3910 | DebugTool.logError(TAG, "notifySppError: Unable to retrieve notification Manager service"); |
3886 | 3911 | } |
3887 | 3912 | } |
| 3913 | + |
| 3914 | + private void showBTPermissionsNotification() { |
| 3915 | + Notification.Builder builder; |
| 3916 | + if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { |
| 3917 | + builder = new Notification.Builder(getApplicationContext()); |
| 3918 | + } else { |
| 3919 | + builder = new Notification.Builder(getApplicationContext(), TransportConstants.SDL_ERROR_NOTIFICATION_CHANNEL_ID); |
| 3920 | + } |
| 3921 | + |
| 3922 | + ComponentName name = new ComponentName(this, this.getClass()); |
| 3923 | + if (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE)) { //If we are in debug mode, include what app has the router service open |
| 3924 | + builder.setContentTitle("SDL: " + name.getPackageName()); |
| 3925 | + } else { |
| 3926 | + builder.setContentTitle(getString(R.string.notification_title)); |
| 3927 | + } |
| 3928 | + builder.setTicker(getString(R.string.sdl_error_notification_channel_name)); |
| 3929 | + builder.setContentText(getString(R.string.allow_bluetooth_permissions)); |
| 3930 | + |
| 3931 | + //We should use icon from library resources if available |
| 3932 | + int trayId = getResources().getIdentifier("sdl_tray_icon", "drawable", getPackageName()); |
| 3933 | + |
| 3934 | + builder.setSmallIcon(trayId); |
| 3935 | + Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.spp_error); |
| 3936 | + builder.setLargeIcon(icon); |
| 3937 | + |
| 3938 | + builder.setOngoing(false); |
| 3939 | + builder.setAutoCancel(true); |
| 3940 | + |
| 3941 | + // Create an intent that will be fired when the user clicks the notification. |
| 3942 | + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); |
| 3943 | + Uri uri = Uri.fromParts("package", getPackageName(), null); |
| 3944 | + intent.setData(uri); |
| 3945 | + int flag = android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_IMMUTABLE : 0; |
| 3946 | + PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, flag); |
| 3947 | + builder.setContentIntent(pendingIntent); |
| 3948 | + |
| 3949 | + final String tag = "SDL"; |
| 3950 | + //Now we need to add a notification channel |
| 3951 | + final NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); |
| 3952 | + if (notificationManager != null) { |
| 3953 | + notificationManager.cancel(tag, TransportConstants.SDL_ERROR_NOTIFICATION_CHANNEL_ID_INT); |
| 3954 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
| 3955 | + NotificationChannel notificationChannel = new NotificationChannel(TransportConstants.SDL_ERROR_NOTIFICATION_CHANNEL_ID, getString(R.string.sdl_error_notification_channel_name), NotificationManager.IMPORTANCE_HIGH); |
| 3956 | + notificationChannel.enableLights(true); |
| 3957 | + notificationChannel.enableVibration(true); |
| 3958 | + notificationChannel.setShowBadge(false); |
| 3959 | + notificationManager.createNotificationChannel(notificationChannel); |
| 3960 | + builder.setChannelId(notificationChannel.getId()); |
| 3961 | + } |
| 3962 | + Notification notification = builder.build(); |
| 3963 | + notificationManager.notify(tag, TransportConstants.SDL_ERROR_NOTIFICATION_CHANNEL_ID_INT, notification); |
| 3964 | + } else { |
| 3965 | + DebugTool.logError(TAG, "Unable to retrieve notification Manager service"); |
| 3966 | + } |
| 3967 | + } |
3888 | 3968 | } |
0 commit comments