From 298704fc77dddee561e436e66833a285ad5dc25d Mon Sep 17 00:00:00 2001
From: Hampus Rosenquist <hamro777@student.liu.se>
Date: Thu, 3 Nov 2022 15:38:27 +0100
Subject: [PATCH] Update runtime permission handling (not done)

---
 .../Android/app/build.gradle                  |  3 +
 .../Android/app/src/main/AndroidManifest.xml  | 11 +++-
 .../dripdronescanner/android/Constants.java   |  3 +-
 .../android/app/AircraftMapView.java          | 35 ++++++++----
 .../android/app/DebugActivity.java            | 57 +++++++++++++++++--
 .../android/network/BluetoothScanner.java     | 37 +++++++-----
 .../app/src/main/res/values/strings.xml       |  2 +
 7 files changed, 118 insertions(+), 30 deletions(-)

diff --git a/drip-android-observer-master/Android/app/build.gradle b/drip-android-observer-master/Android/app/build.gradle
index af1ced4..dd176fa 100644
--- a/drip-android-observer-master/Android/app/build.gradle
+++ b/drip-android-observer-master/Android/app/build.gradle
@@ -20,12 +20,15 @@ android {
         versionName "${versionMajor}.${versionMinor}.${versionPatch}"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }
+
     buildTypes {
         debug {
             versionNameSuffix ".debug"
             resValue "string", "app_version", "${defaultConfig.versionName}${versionNameSuffix}"
         }
         release {
+            //signingConfig signingConfigs.release
+            //debuggable false
             resValue "string", "app_version", "${defaultConfig.versionName}"
             minifyEnabled false
             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
diff --git a/drip-android-observer-master/Android/app/src/main/AndroidManifest.xml b/drip-android-observer-master/Android/app/src/main/AndroidManifest.xml
index 7202089..729e8bc 100644
--- a/drip-android-observer-master/Android/app/src/main/AndroidManifest.xml
+++ b/drip-android-observer-master/Android/app/src/main/AndroidManifest.xml
@@ -2,10 +2,17 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools">
 
-    <uses-permission android:name="android.permission.BLUETOOTH" />
-    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+    <!-- Request legacy Bluetooth permissions on older devices. -->
+    <uses-permission android:name="android.permission.BLUETOOTH"
+        android:maxSdkVersion="30"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
+        android:maxSdkVersion="30"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
+
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
diff --git a/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/Constants.java b/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/Constants.java
index b26ddd0..6ee5117 100644
--- a/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/Constants.java
+++ b/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/Constants.java
@@ -7,9 +7,10 @@
 package org.dripdronescanner.android;
 
 public class Constants {
-    public static final int REQUEST_ENABLE_BT = 1;
+    public static final int REQUEST_BT_CONNECT = 1;
     public static final int FINE_LOCATION_PERMISSION_REQUEST_CODE = 2;
     public static final int REQUEST_ENABLE_WIFI = 3;
+    public static final int REQUEST_BT_SCAN = 4;
 
     public static final String DELIM = ",";
 
diff --git a/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/app/AircraftMapView.java b/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/app/AircraftMapView.java
index 0fcab57..72f5f06 100644
--- a/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/app/AircraftMapView.java
+++ b/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/app/AircraftMapView.java
@@ -11,6 +11,8 @@ import android.view.ViewGroup;
 import android.util.Log;
 import android.widget.ImageButton;
 
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
 import androidx.core.app.ActivityCompat;
 import androidx.core.content.res.ResourcesCompat;
 import androidx.fragment.app.Fragment;
@@ -18,6 +20,8 @@ import androidx.annotation.Nullable;
 import androidx.lifecycle.Observer;
 import androidx.lifecycle.ViewModelProvider;
 
+import org.dripdronescanner.android.Constants;
+import org.dripdronescanner.android.PermissionUtils;
 import org.dripdronescanner.android.R;
 import org.dripdronescanner.android.data.AircraftObject;
 import org.dripdronescanner.android.data.LocationData;
@@ -87,15 +91,12 @@ public class AircraftMapView extends Fragment {
             if (getActivity() == null)
                 return;
 
+            map.setMultiTouchControls(true);
+            map.getController().setZoom(DESIRED_ZOOM);
+
             if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                     ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
-                // TODO: Consider calling ActivityCompat#requestPermissions
-                // to request the missing permissions, and then overriding
-                //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
-                //                                          int[] grantResults)
-                // to handle the case where the user grants the permission. See the documentation
-                // for ActivityCompat#requestPermissions for more details.
-                Log.e("XX", "##################### can't make the right permissions");
+                requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION);
                 return;
             }
 
@@ -103,9 +104,6 @@ public class AircraftMapView extends Fragment {
             overlay.enableMyLocation();
             overlay.enableFollowLocation();
             map.getOverlays().add(overlay);
-
-            map.setMultiTouchControls(true);
-            map.getController().setZoom(DESIRED_ZOOM);
         });
 
         ImageButton centerMapButton = v.findViewById(R.id.ic_center_map);
@@ -300,4 +298,21 @@ public class AircraftMapView extends Fragment {
             }
         }
     }
+
+    private final ActivityResultLauncher<String> requestPermissionLauncher =
+            registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
+                if (isGranted) {
+                    overlay = new MyLocationNewOverlay(new GpsMyLocationProvider(requireContext()), map);
+                    overlay.enableMyLocation();
+                    overlay.enableFollowLocation();
+                    map.getOverlays().add(overlay);
+                } else {
+                    //showErrorText(R.string.permission_required_toast);
+                    // Explain to the user that the feature is unavailable because the
+                    // feature requires a permission that the user has denied. At the
+                    // same time, respect the user's decision. Don't link to system
+                    // settings in an effort to convince the user to change their
+                    // decision.
+                }
+            });
 }
\ No newline at end of file
diff --git a/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/app/DebugActivity.java b/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/app/DebugActivity.java
index c12d40e..04fbd61 100644
--- a/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/app/DebugActivity.java
+++ b/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/app/DebugActivity.java
@@ -28,6 +28,7 @@ import android.widget.Toast;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.core.app.ActivityCompat;
 import androidx.fragment.app.FragmentTransaction;
@@ -91,7 +92,7 @@ public class DebugActivity extends AppCompatActivity {
         return true;
     }
 
-    private void createSettingsItem(Menu menu){
+    private void createSettingsItem(Menu menu) {
         DebugActivity current = this;
         MenuItem settings = menu.findItem(R.id.settings);
         settings.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@@ -111,7 +112,7 @@ public class DebugActivity extends AppCompatActivity {
             return;
         BluetoothAdapter bluetoothAdapter = ((android.bluetooth.BluetoothManager) object).getAdapter();
 
-        if(bluetoothAdapter != null) {
+        if (bluetoothAdapter != null) {
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && bluetoothAdapter.isLeCodedPhySupported()) {
                 menu.findItem(R.id.coded_phy).setTitle(R.string.coded_phy_supported);
             }
@@ -127,6 +128,7 @@ public class DebugActivity extends AppCompatActivity {
             menu.findItem(R.id.wifi_nan).setTitle(R.string.nan_supported);
         }
     }
+
     @TargetApi(Build.VERSION_CODES.M)
     private void checkWiFiSupport(Menu menu) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
@@ -188,6 +190,12 @@ public class DebugActivity extends AppCompatActivity {
     }
 
     private void createNewLogfile() {
+        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+                requestBluetoothConnectPermission(Constants.REQUEST_BT_CONNECT);
+            }
+            return;
+        }
         loggerFile = getLoggerFileDir(btScanner.getBluetoothAdapter().getName());
 
         try {
@@ -235,7 +243,7 @@ public class DebugActivity extends AppCompatActivity {
             if (!bluetoothAdapter.isEnabled()) {
                 // Prompt user to turn on Bluetooth (logic continues in onActivityResult()).
                 Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
-                startActivityForResult(enableBtIntent, Constants.REQUEST_ENABLE_BT);
+                startActivityForResult(enableBtIntent, Constants.REQUEST_BT_CONNECT);
             } else {
                 bluetoothOn = true;
                 // Check permission
@@ -288,6 +296,12 @@ public class DebugActivity extends AppCompatActivity {
 
         mModel.getAllAircraft().observe(this, listObserver);
 
+        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+                requestBluetoothScanPermission(Constants.REQUEST_BT_SCAN);
+            }
+            return;
+        }
         btScanner.startScan();
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -307,7 +321,7 @@ public class DebugActivity extends AppCompatActivity {
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
-        if (requestCode == Constants.REQUEST_ENABLE_BT) {
+        if (requestCode == Constants.REQUEST_BT_CONNECT) {
                 if (resultCode == RESULT_OK) {
                     if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                             && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
@@ -375,9 +389,28 @@ public class DebugActivity extends AppCompatActivity {
                 Manifest.permission.ACCESS_FINE_LOCATION, false);
     }
 
+    @RequiresApi(api = Build.VERSION_CODES.S)
+    public void requestBluetoothConnectPermission(int requestCode) {
+        Log.d(TAG, "requestBluetoothConnectPermission: request permission");
+
+        // Bluetooth permission has not been granted yet, request it.
+        PermissionUtils.requestPermission(this, requestCode,
+                Manifest.permission.BLUETOOTH_CONNECT, false);
+    }
+
+    @RequiresApi(api = Build.VERSION_CODES.S)
+    public void requestBluetoothScanPermission(int requestCode) {
+        Log.d(TAG, "requestBluetoothConnectPermission: request permission");
+
+        // Bluetooth permission has not been granted yet, request it.
+        PermissionUtils.requestPermission(this, requestCode,
+                Manifest.permission.BLUETOOTH_SCAN, false);
+    }
+
     @Override
     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                            @NonNull int[] grantResults) {
+        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
         if (requestCode == Constants.FINE_LOCATION_PERMISSION_REQUEST_CODE) {
             Log.d(TAG, "onRequestPermissionsResult: back from request FINE_LOCATION");
             if (PermissionUtils.isPermissionGranted(permissions, grantResults,
@@ -387,6 +420,22 @@ public class DebugActivity extends AppCompatActivity {
                 showErrorText(R.string.permission_required_toast);
             }
 
+        } else if (requestCode == Constants.REQUEST_BT_CONNECT) {
+            Log.d(TAG, "onRequestPermissionsResult: back from request BLUETOOTH_CONNECT");
+            if (PermissionUtils.isPermissionGranted(permissions, grantResults,
+                    Manifest.permission.BLUETOOTH_CONNECT)) {
+                initialize();
+            } else {
+                showErrorText(R.string.bluetooth_connect_permission_required_toast);
+            }
+        } else if (requestCode == Constants.REQUEST_BT_SCAN) {
+            Log.d(TAG, "onRequestPermissionsResult: back from request BLUETOOTH_SCAN");
+            if (PermissionUtils.isPermissionGranted(permissions, grantResults,
+                    Manifest.permission.BLUETOOTH_SCAN)) {
+                initialize();
+            } else {
+                showErrorText(R.string.bluetooth_scan_permission_required_toast);
+            }
         }
     }
 }
diff --git a/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/network/BluetoothScanner.java b/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/network/BluetoothScanner.java
index a554191..5c90c88 100644
--- a/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/network/BluetoothScanner.java
+++ b/drip-android-observer-master/Android/app/src/main/java/org/dripdronescanner/android/network/BluetoothScanner.java
@@ -6,6 +6,7 @@
  */
 package org.dripdronescanner.android.network;
 
+import android.Manifest;
 import android.annotation.TargetApi;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
@@ -16,10 +17,16 @@ import android.bluetooth.le.ScanRecord;
 import android.bluetooth.le.ScanResult;
 import android.bluetooth.le.ScanSettings;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.ParcelUuid;
 import android.util.Log;
 
+import androidx.annotation.RequiresApi;
+import androidx.core.app.ActivityCompat;
+
+import org.dripdronescanner.android.PermissionUtils;
+import org.dripdronescanner.android.app.DebugActivity;
 import org.dripdronescanner.android.log.LogEntry;
 import org.dripdronescanner.android.log.LogMessageEntry;
 import org.dripdronescanner.android.log.LogWriter;
@@ -47,7 +54,9 @@ public class BluetoothScanner {
         bluetoothAdapter = ((android.bluetooth.BluetoothManager) object).getAdapter();
     }
 
-    public void setLogger(LogWriter logger) { this.logger = logger; }
+    public void setLogger(LogWriter logger) {
+        this.logger = logger;
+    }
 
     private static String dumpBytes(byte[] bytes) {
         return LogEntry.toHexString(bytes, bytes.length);
@@ -72,7 +81,7 @@ public class BluetoothScanner {
                     addr, advertiseFlags, rssi, bytes != null ? bytes.length : -1);
 
             String transportType = "BT4";
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && bluetoothAdapter.isLeCodedPhySupported()) {
+            if (bluetoothAdapter.isLeCodedPhySupported()) {
                 if (result.getPrimaryPhy() == BluetoothDevice.PHY_LE_CODED)
                     transportType = "BT5";
             }
@@ -110,7 +119,6 @@ public class BluetoothScanner {
     private static final ParcelUuid SERVICE_pUUID = new ParcelUuid(SERVICE_UUID);
     private static final byte[] OPEN_DRONE_ID_AD_CODE = new byte[]{(byte) 0x0D};
 
-    @TargetApi(Build.VERSION_CODES.O)
     public void startScan() {
         if (bluetoothAdapter == null)
             return;
@@ -124,24 +132,27 @@ public class BluetoothScanner {
         scanFilters.add(builder.build());
 
         ScanSettings scanSettings = new ScanSettings.Builder()
-                                    .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
-                                    .build();
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
-            bluetoothAdapter.isLeCodedPhySupported() &&
-            bluetoothAdapter.isLeExtendedAdvertisingSupported()) {
+                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
+                .build();
+        if (bluetoothAdapter.isLeCodedPhySupported() && bluetoothAdapter.isLeExtendedAdvertisingSupported()) {
             // Enable scanning also for devices advertising on an LE Coded PHY S2 or S8
             scanSettings = new ScanSettings.Builder()
-                           .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
-                           .setLegacy(false)
-                           .setPhy(ScanSettings.PHY_LE_ALL_SUPPORTED)
-                           .build();
+                    .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
+                    .setLegacy(false)
+                    .setPhy(ScanSettings.PHY_LE_ALL_SUPPORTED)
+                    .build();
+        }
+        if (ActivityCompat.checkSelfPermission(con, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
+            return;
         }
-
         bluetoothLeScanner.startScan(scanFilters, scanSettings, scanCallback);
     }
 
     public void stopScan() {
         if (bluetoothLeScanner != null && scanCallback != null) {
+            if (ActivityCompat.checkSelfPermission(con, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
+                return;
+            }
             bluetoothLeScanner.stopScan(scanCallback);
         }
     }
diff --git a/drip-android-observer-master/Android/app/src/main/res/values/strings.xml b/drip-android-observer-master/Android/app/src/main/res/values/strings.xml
index 5346aa2..990009d 100644
--- a/drip-android-observer-master/Android/app/src/main/res/values/strings.xml
+++ b/drip-android-observer-master/Android/app/src/main/res/values/strings.xml
@@ -41,6 +41,8 @@
     <string name="permission_rationale_location">Access to the location service is required to demonstrate the \'my location\' feature, which shows your current location on the map.</string>
     <string name="location_permission_denied">This sample requires location permission to enable the \'my location\' layer. Please try again and grant access to use the location.\nIf the permission has been permanently denied, it can be enabled from the System Settings &gt; Apps &gt; \'Google Maps API Demos\'.</string>
     <string name="permission_required_toast">Location permission is required for Bluetooth advertising scanning.</string>
+    <string name="bluetooth_connect_permission_required_toast">Bluetooth connect permission is required for Bluetooth connectivity.</string>
+    <string name="bluetooth_scan_permission_required_toast">Bluetooth scan permission is required for Bluetooth connectivity.</string>
 
     <string name="drone_icon_content_description">Drone icon</string>
 
-- 
GitLab