1
0
mirror of https://github.com/oliexdev/openScale.git synced 2025-08-18 06:21:25 +02:00

update request runtime permissions to new Android methods

This commit is contained in:
oliexdev
2023-01-20 14:01:03 +01:00
parent 83c2d941ea
commit a59a96151e
5 changed files with 314 additions and 275 deletions

View File

@@ -2,12 +2,12 @@ apply plugin: 'com.android.application'
apply plugin: "androidx.navigation.safeargs" apply plugin: "androidx.navigation.safeargs"
android { android {
compileSdkVersion 32 compileSdkVersion 33
defaultConfig { defaultConfig {
applicationId "com.health.openscale" applicationId "com.health.openscale"
testApplicationId "com.health.openscale.test" testApplicationId "com.health.openscale.test"
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 32 targetSdkVersion 33
versionCode 61 versionCode 61
versionName "2.4.6" versionName "2.4.6"
@@ -139,9 +139,9 @@ android {
dependencies { dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
implementation 'com.google.android.material:material:1.8.0-alpha03' implementation 'com.google.android.material:material:1.8.0-rc01'
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.appcompat:appcompat:1.5.1' implementation 'androidx.appcompat:appcompat:1.6.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.preference:preference:1.2.0' implementation 'androidx.preference:preference:1.2.0'

View File

@@ -18,6 +18,7 @@ package com.health.openscale.gui;
import android.Manifest; import android.Manifest;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothManager;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
@@ -28,12 +29,14 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.location.LocationManager;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.Settings;
import android.text.Editable; import android.text.Editable;
import android.text.Html; import android.text.Html;
import android.text.InputFilter; import android.text.InputFilter;
@@ -51,10 +54,13 @@ import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate; import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider; import androidx.core.content.FileProvider;
import androidx.core.view.GravityCompat; import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout; import androidx.drawerlayout.widget.DrawerLayout;
@@ -77,7 +83,6 @@ import com.health.openscale.gui.measurement.MeasurementEntryFragment;
import com.health.openscale.gui.preferences.BluetoothSettingsFragment; import com.health.openscale.gui.preferences.BluetoothSettingsFragment;
import com.health.openscale.gui.preferences.UserSettingsFragment; import com.health.openscale.gui.preferences.UserSettingsFragment;
import com.health.openscale.gui.slides.AppIntroActivity; import com.health.openscale.gui.slides.AppIntroActivity;
import com.health.openscale.gui.utils.PermissionHelper;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@@ -100,7 +105,6 @@ public class MainActivity extends AppCompatActivity
private static final int IMPORT_DATA_REQUEST = 100; private static final int IMPORT_DATA_REQUEST = 100;
private static final int EXPORT_DATA_REQUEST = 101; private static final int EXPORT_DATA_REQUEST = 101;
private static final int ENABLE_BLUETOOTH_REQUEST = 102;
private static final int APPINTRO_REQUEST = 103; private static final int APPINTRO_REQUEST = 103;
private AppBarConfiguration mAppBarConfiguration; private AppBarConfiguration mAppBarConfiguration;
@@ -532,7 +536,6 @@ public class MainActivity extends AppCompatActivity
boolean hasBluetooth = bluetoothManager.getAdapter() != null; boolean hasBluetooth = bluetoothManager.getAdapter() != null;
if (!hasBluetooth) { if (!hasBluetooth) {
bluetoothStatus.setEnabled(false);
setBluetoothStatusIcon(R.drawable.ic_bluetooth_disabled); setBluetoothStatusIcon(R.drawable.ic_bluetooth_disabled);
} }
// Just search for a bluetooth device just once at the start of the app and if start preference enabled // Just search for a bluetooth device just once at the start of the app and if start preference enabled
@@ -571,6 +574,54 @@ public class MainActivity extends AppCompatActivity
return; return;
} }
Timber.d("Main Activity Bluetooth permission check");
int targetSdkVersion = getApplicationInfo().targetSdkVersion;
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter btAdapter = bluetoothManager.getAdapter();
// Check if Bluetooth is enabled
if (btAdapter == null || !btAdapter.isEnabled()) {
Timber.d("Bluetooth is not enabled");
Toast.makeText(this, "Bluetooth " + getResources().getString(R.string.info_is_not_enable), Toast.LENGTH_SHORT).show();
setBluetoothStatusIcon(R.drawable.ic_bluetooth_disabled);
return;
}
// Check if Bluetooth 4.x is available
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Timber.d("No Bluetooth 4.x available");
Toast.makeText(this, "Bluetooth 4.x " + getResources().getString(R.string.info_is_not_available), Toast.LENGTH_SHORT).show();
setBluetoothStatusIcon(R.drawable.ic_bluetooth_disabled);
return;
}
// Check if GPS or Network location service is enabled
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
if (!(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER))) {
Timber.d("No GPS or Network location service is enabled, ask user for permission");
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.permission_bluetooth_info_title);
builder.setIcon(R.drawable.ic_preferences_about);
builder.setMessage(R.string.permission_location_service_info);
builder.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
// Show location settings when the user acknowledges the alert dialog
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
});
Dialog alertDialog = builder.create();
alertDialog.setCanceledOnTouchOutside(false);
alertDialog.show();
setBluetoothStatusIcon(R.drawable.ic_bluetooth_disabled);
return;
}
String deviceName = prefs.getString( String deviceName = prefs.getString(
BluetoothSettingsFragment.PREFERENCE_KEY_BLUETOOTH_DEVICE_NAME, ""); BluetoothSettingsFragment.PREFERENCE_KEY_BLUETOOTH_DEVICE_NAME, "");
String hwAddress = prefs.getString( String hwAddress = prefs.getString(
@@ -582,21 +633,58 @@ public class MainActivity extends AppCompatActivity
return; return;
} }
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); String[] requiredPermissions;
if (!bluetoothManager.getAdapter().isEnabled()) {
setBluetoothStatusIcon(R.drawable.ic_bluetooth_connection_lost);
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, ENABLE_BLUETOOTH_REQUEST);
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.S) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && targetSdkVersion >= Build.VERSION_CODES.S) {
Timber.d("SDK >= 31 request for Bluetooth Scan and Bluetooth connect permissions"); Timber.d("SDK >= 31 request for Bluetooth Scan and Bluetooth connect permissions");
requestPermissions(new String[]{Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT}, PermissionHelper.PERMISSIONS_REQUEST_ACCESS_BLUETOOTH); requiredPermissions = new String[]{Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT};
return; } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && targetSdkVersion >= Build.VERSION_CODES.Q) {
Timber.d("SDK >= 29 request for Access fine location permission");
requiredPermissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
} else {
Timber.d("SDK < 29 request for coarse location permission");
requiredPermissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
} }
connectToBluetooth(); if (hasPermissions(requiredPermissions)) {
connectToBluetooth();
} else if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
Timber.d("No access fine location permission granted");
builder.setMessage(R.string.permission_bluetooth_info)
.setTitle(R.string.permission_bluetooth_info_title)
.setIcon(R.drawable.ic_preferences_about)
.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
requestPermissionBluetoothLauncher.launch(requiredPermissions);
}
});
Dialog alertDialog = builder.create();
alertDialog.setCanceledOnTouchOutside(false);
alertDialog.show();
} else if (shouldShowRequestPermissionRationale(Manifest.permission.BLUETOOTH_SCAN)) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
Timber.d("No access Bluetooth scan permission granted");
builder.setMessage(R.string.permission_bluetooth_info)
.setTitle(R.string.permission_bluetooth_info_title)
.setIcon(R.drawable.ic_preferences_about)
.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
requestPermissionBluetoothLauncher.launch(requiredPermissions);
}
});
Dialog alertDialog = builder.create();
alertDialog.setCanceledOnTouchOutside(false);
alertDialog.show();
} else {
requestPermissionBluetoothLauncher.launch(requiredPermissions);
}
} }
private void connectToBluetooth() { private void connectToBluetooth() {
@@ -900,48 +988,12 @@ public class MainActivity extends AppCompatActivity
startActivity(Intent.createChooser(intent, getResources().getString(R.string.label_share))); startActivity(Intent.createChooser(intent, getResources().getString(R.string.label_share)));
} }
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PermissionHelper.PERMISSIONS_REQUEST_ACCESS_BLUETOOTH: {
boolean allGranted = true;
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
allGranted = false;
break;
}
}
if (allGranted) {
Timber.d("All Bluetooth permissions granted");
connectToBluetooth();
} else {
Timber.d("At least one Bluetooth permission was not granted");
Toast.makeText(this, R.string.permission_not_granted, Toast.LENGTH_SHORT).show();
}
break;
}
}
}
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
OpenScale openScale = OpenScale.getInstance(); OpenScale openScale = OpenScale.getInstance();
if (requestCode == ENABLE_BLUETOOTH_REQUEST) {
if (resultCode == RESULT_OK) {
invokeConnectToBluetoothDevice();
}
else {
Toast.makeText(this, "Bluetooth " + getResources().getString(R.string.info_is_not_enable), Toast.LENGTH_SHORT).show();
}
return;
}
if (requestCode == APPINTRO_REQUEST) { if (requestCode == APPINTRO_REQUEST) {
if (openScale.getSelectedScaleUserId() == -1) { if (openScale.getSelectedScaleUserId() == -1) {
MobileNavigationDirections.ActionNavMobileNavigationToNavUsersettings action = MobileNavigationDirections.actionNavMobileNavigationToNavUsersettings(); MobileNavigationDirections.ActionNavMobileNavigationToNavUsersettings action = MobileNavigationDirections.actionNavMobileNavigationToNavUsersettings();
@@ -992,4 +1044,29 @@ public class MainActivity extends AppCompatActivity
break; break;
} }
} }
private boolean hasPermissions(String[] permissions) {
if (permissions != null) {
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
Timber.d("Permission is not granted: " + permission);
return false;
}
Timber.d("Permission already granted: " + permission);
}
return true;
}
return false;
}
private ActivityResultLauncher<String[]> requestPermissionBluetoothLauncher =
registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), isGranted -> {
if (isGranted.containsValue(false)) {
Timber.d("At least one Bluetooth permission was not granted");
Toast.makeText(this, getString(R.string.label_bluetooth_title) + ": " + getString(R.string.permission_not_granted), Toast.LENGTH_SHORT).show();
}
else {
connectToBluetooth();
}
});
} }

View File

@@ -17,6 +17,7 @@ package com.health.openscale.gui.preferences;
import static android.app.Activity.RESULT_OK; import static android.app.Activity.RESULT_OK;
import android.Manifest;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@@ -28,6 +29,9 @@ import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.widget.Toast; import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.preference.CheckBoxPreference; import androidx.preference.CheckBoxPreference;
import androidx.preference.Preference; import androidx.preference.Preference;
@@ -37,7 +41,6 @@ import com.health.openscale.R;
import com.health.openscale.core.OpenScale; import com.health.openscale.core.OpenScale;
import com.health.openscale.core.alarm.AlarmBackupHandler; import com.health.openscale.core.alarm.AlarmBackupHandler;
import com.health.openscale.core.alarm.ReminderBootReceiver; import com.health.openscale.core.alarm.ReminderBootReceiver;
import com.health.openscale.gui.utils.PermissionHelper;
import java.io.IOException; import java.io.IOException;
@@ -138,7 +141,12 @@ public class BackupPreferences extends PreferenceFragmentCompat implements Share
if (autoBackup.isChecked()) { if (autoBackup.isChecked()) {
isAutoBackupAskForPermission = true; isAutoBackupAskForPermission = true;
PermissionHelper.requestWritePermission(fragment); if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
exportBackup();
} else {
requestPermissionExportLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
} }
} }
return true; return true;
@@ -148,10 +156,16 @@ public class BackupPreferences extends PreferenceFragmentCompat implements Share
private class onClickListenerImportBackup implements Preference.OnPreferenceClickListener { private class onClickListenerImportBackup implements Preference.OnPreferenceClickListener {
@Override @Override
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
if (PermissionHelper.requestReadPermission(fragment)) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
importBackup(); importBackup();
} else {
if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
importBackup();
} else {
requestPermissionImportLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE);
}
} }
return true; return true;
} }
} }
@@ -161,8 +175,13 @@ public class BackupPreferences extends PreferenceFragmentCompat implements Share
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
exportBackup(); exportBackup();
} else if (PermissionHelper.requestWritePermission(fragment)) { } else {
exportBackup(); if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
exportBackup();
} else {
requestPermissionExportLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
} }
return true; return true;
@@ -232,36 +251,35 @@ public class BackupPreferences extends PreferenceFragmentCompat implements Share
} }
@Override @Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
switch (requestCode) { menu.clear();
case PermissionHelper.PERMISSIONS_REQUEST_ACCESS_READ_STORAGE: }
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
private ActivityResultLauncher<String> requestPermissionImportLauncher =
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
if (isGranted) {
importBackup(); importBackup();
} else { }
else {
Toast.makeText(getContext(), getResources().getString(R.string.permission_not_granted), Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), getResources().getString(R.string.permission_not_granted), Toast.LENGTH_SHORT).show();
} }
break; });
case PermissionHelper.PERMISSIONS_REQUEST_ACCESS_WRITE_STORAGE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { private ActivityResultLauncher<String> requestPermissionExportLauncher =
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
if (isGranted) {
if (isAutoBackupAskForPermission) { if (isAutoBackupAskForPermission) {
autoBackup.setChecked(true); autoBackup.setChecked(true);
} else { } else {
exportBackup(); exportBackup();
} }
}
} else { else {
if (isAutoBackupAskForPermission) { if (isAutoBackupAskForPermission) {
autoBackup.setChecked(false); autoBackup.setChecked(false);
} }
Toast.makeText(getContext(), getResources().getString(R.string.permission_not_granted), Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), getResources().getString(R.string.permission_not_granted), Toast.LENGTH_SHORT).show();
} }
break; });
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
}
} }

View File

@@ -15,9 +15,14 @@
*/ */
package com.health.openscale.gui.preferences; package com.health.openscale.gui.preferences;
import android.app.Activity; import static android.content.Context.LOCATION_SERVICE;
import android.Manifest;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanResult;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
@@ -26,12 +31,15 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.location.LocationManager;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.Settings;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.Spanned; import android.text.Spanned;
import android.text.style.ForegroundColorSpan; import android.text.style.ForegroundColorSpan;
@@ -48,6 +56,9 @@ import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation; import androidx.navigation.Navigation;
@@ -56,7 +67,6 @@ import com.health.openscale.core.OpenScale;
import com.health.openscale.core.bluetooth.BluetoothCommunication; import com.health.openscale.core.bluetooth.BluetoothCommunication;
import com.health.openscale.core.bluetooth.BluetoothFactory; import com.health.openscale.core.bluetooth.BluetoothFactory;
import com.health.openscale.gui.utils.ColorUtil; import com.health.openscale.gui.utils.ColorUtil;
import com.health.openscale.gui.utils.PermissionHelper;
import com.welie.blessed.BluetoothCentralManager; import com.welie.blessed.BluetoothCentralManager;
import com.welie.blessed.BluetoothCentralManagerCallback; import com.welie.blessed.BluetoothCentralManagerCallback;
import com.welie.blessed.BluetoothPeripheral; import com.welie.blessed.BluetoothPeripheral;
@@ -99,11 +109,110 @@ public class BluetoothSettingsFragment extends Fragment {
@Override @Override
public void onResume() { public void onResume() {
if (PermissionHelper.requestBluetoothPermission(this)) { super.onResume();
startBluetoothDiscovery();
Timber.d("Bluetooth settings Bluetooth permission check");
int targetSdkVersion = getActivity().getApplicationInfo().targetSdkVersion;
final BluetoothManager bluetoothManager = (BluetoothManager) getActivity().getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter btAdapter = bluetoothManager.getAdapter();
// Check if Bluetooth is enabled
if (btAdapter == null || !btAdapter.isEnabled()) {
Timber.d("Bluetooth is not enabled");
Toast.makeText(getContext(), "Bluetooth " + getContext().getResources().getString(R.string.info_is_not_enable), Toast.LENGTH_SHORT).show();
stepNavigationBack();
return;
} }
super.onResume(); // Check if Bluetooth 4.x is available
if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Timber.d("No Bluetooth 4.x available");
Toast.makeText(getContext(), "Bluetooth 4.x " + getContext().getResources().getString(R.string.info_is_not_available), Toast.LENGTH_SHORT).show();
stepNavigationBack();
return;
}
// Check if GPS or Network location service is enabled
LocationManager locationManager = (LocationManager) getActivity().getSystemService(LOCATION_SERVICE);
if (!(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER))) {
Timber.d("No GPS or Network location service is enabled, ask user for permission");
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(R.string.permission_bluetooth_info_title);
builder.setIcon(R.drawable.ic_preferences_about);
builder.setMessage(R.string.permission_location_service_info);
builder.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
// Show location settings when the user acknowledges the alert dialog
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
getActivity().startActivity(intent);
}
});
Dialog alertDialog = builder.create();
alertDialog.setCanceledOnTouchOutside(false);
alertDialog.show();
stepNavigationBack();
return;
}
String[] requiredPermissions;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && targetSdkVersion >= Build.VERSION_CODES.S) {
Timber.d("SDK >= 31 request for Bluetooth Scan and Bluetooth connect permissions");
requiredPermissions = new String[]{Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT};
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && targetSdkVersion >= Build.VERSION_CODES.Q) {
Timber.d("SDK >= 29 request for Access fine location permission");
requiredPermissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
} else {
Timber.d("SDK < 29 request for coarse location permission");
requiredPermissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
}
if (hasPermissions(requiredPermissions)) {
startBluetoothDiscovery();
} else if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
Timber.d("No access fine location permission granted");
builder.setMessage(R.string.permission_bluetooth_info)
.setTitle(R.string.permission_bluetooth_info_title)
.setIcon(R.drawable.ic_preferences_about)
.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
requestPermissionBluetoothLauncher.launch(requiredPermissions);
}
});
Dialog alertDialog = builder.create();
alertDialog.setCanceledOnTouchOutside(false);
alertDialog.show();
} else if (shouldShowRequestPermissionRationale(Manifest.permission.BLUETOOTH_SCAN)) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
Timber.d("No access Bluetooth scan permission granted");
builder.setMessage(R.string.permission_bluetooth_info)
.setTitle(R.string.permission_bluetooth_info_title)
.setIcon(R.drawable.ic_preferences_about)
.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
requestPermissionBluetoothLauncher.launch(requiredPermissions);
}
});
Dialog alertDialog = builder.create();
alertDialog.setCanceledOnTouchOutside(false);
alertDialog.show();
} else {
requestPermissionBluetoothLauncher.launch(requiredPermissions);
}
} }
@Override @Override
@@ -375,47 +484,38 @@ public class BluetoothSettingsFragment extends Fragment {
} }
} }
@Override private void stepNavigationBack() {
public void onActivityResult(int requestCode, int resultCode, Intent data) { if (getActivity().findViewById(R.id.nav_host_fragment) != null) {
if (requestCode == PermissionHelper.ENABLE_BLUETOOTH_REQUEST) { Navigation.findNavController(requireActivity(), R.id.nav_host_fragment).getPreviousBackStackEntry().getSavedStateHandle().set("update", true);
if (resultCode == Activity.RESULT_OK) { Navigation.findNavController(requireActivity(), R.id.nav_host_fragment).navigateUp();
if (PermissionHelper.requestBluetoothPermission(this)) { } else {
startBluetoothDiscovery(); getActivity().finish();
}
}
} }
super.onActivityResult(requestCode, resultCode, data);
} }
@Override private boolean hasPermissions(String[] permissions) {
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { if (permissions != null) {
switch (requestCode) { for (String permission : permissions) {
case PermissionHelper.PERMISSIONS_REQUEST_ACCESS_BLUETOOTH: { if (ContextCompat.checkSelfPermission(getContext(), permission) != PackageManager.PERMISSION_GRANTED) {
boolean allGranted = true; Timber.d("Permission is not granted: " + permission);
for (int result : grantResults) { return false;
if (result != PackageManager.PERMISSION_GRANTED) {
allGranted = false;
break;
}
} }
Timber.d("Permission already granted: " + permission);
}
return true;
}
return false;
}
if (allGranted) { private ActivityResultLauncher<String[]> requestPermissionBluetoothLauncher =
Timber.d("All Bluetooth permissions granted"); registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), isGranted -> {
startBluetoothDiscovery(); if (isGranted.containsValue(false)) {
} else {
Timber.d("At least one Bluetooth permission was not granted"); Timber.d("At least one Bluetooth permission was not granted");
Toast.makeText(requireContext(), R.string.permission_not_granted, Toast.LENGTH_SHORT).show(); Toast.makeText(requireContext(), getString(R.string.label_bluetooth_title) + ": " + getString(R.string.permission_not_granted), Toast.LENGTH_SHORT).show();
stepNavigationBack();
if (getActivity().findViewById(R.id.nav_host_fragment) != null){
Navigation.findNavController(requireActivity(), R.id.nav_host_fragment).getPreviousBackStackEntry().getSavedStateHandle().set("update", true);
Navigation.findNavController(requireActivity(), R.id.nav_host_fragment).navigateUp();
} else {
getActivity().finish();
}
} }
break; else {
} startBluetoothDiscovery();
} }
} });
} }

View File

@@ -1,156 +0,0 @@
/* Copyright (C) 2018 olie.xdev <olie.xdev@googlemail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.health.openscale.gui.utils;
import static android.content.Context.LOCATION_SERVICE;
import android.Manifest;
import android.app.AlertDialog;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.os.Build;
import android.provider.Settings;
import android.widget.Toast;
import androidx.fragment.app.Fragment;
import com.health.openscale.R;
import timber.log.Timber;
public class PermissionHelper {
public final static int PERMISSIONS_REQUEST_ACCESS_BLUETOOTH = 1;
public final static int PERMISSIONS_REQUEST_ACCESS_READ_STORAGE = 2;
public final static int PERMISSIONS_REQUEST_ACCESS_WRITE_STORAGE = 3;
public final static int ENABLE_BLUETOOTH_REQUEST = 5;
public static boolean requestBluetoothPermission(final Fragment fragment) {
final BluetoothManager bluetoothManager = (BluetoothManager) fragment.getActivity().getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter btAdapter = bluetoothManager.getAdapter();
if (btAdapter == null || !btAdapter.isEnabled()) {
Toast.makeText(fragment.getContext(), "Bluetooth " + fragment.getContext().getResources().getString(R.string.info_is_not_enable), Toast.LENGTH_SHORT).show();
if (btAdapter != null) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
fragment.getActivity().startActivityForResult(enableBtIntent, ENABLE_BLUETOOTH_REQUEST);
}
return false;
}
// Check if Bluetooth 4.x is available
if (!fragment.getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(fragment.getContext(), "Bluetooth 4.x " + fragment.getContext().getResources().getString(R.string.info_is_not_available), Toast.LENGTH_SHORT).show();
return false;
}
int targetSdkVersion = fragment.getActivity().getApplicationInfo().targetSdkVersion;
String[] requiredPermissions;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && targetSdkVersion >= Build.VERSION_CODES.S) {
Timber.d("SDK >= 31 request for Bluetooth Scan and Bluetooth connect permissions");
requiredPermissions = new String[]{Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT};
fragment.requestPermissions(requiredPermissions, PERMISSIONS_REQUEST_ACCESS_BLUETOOTH);
return false;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && targetSdkVersion >= Build.VERSION_CODES.Q) {
Timber.d("SDK >= 29 request for Access fine location permission");
return requestLocationPermission(fragment, new String[]{Manifest.permission.ACCESS_FINE_LOCATION});
} else {
Timber.d("SDK < 29 request for coarse location permission");
return requestLocationPermission(fragment, new String[]{Manifest.permission.ACCESS_FINE_LOCATION});
}
}
private static boolean requestLocationPermission(final Fragment fragment, String[] requiredPermissions) {
if (requestLocationServicePermission(fragment)) {
if (fragment.getContext().checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getActivity());
Timber.d("No access fine location permission granted");
builder.setMessage(R.string.permission_bluetooth_info)
.setTitle(R.string.permission_bluetooth_info_title)
.setIcon(R.drawable.ic_preferences_about)
.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
fragment.requestPermissions(requiredPermissions, PERMISSIONS_REQUEST_ACCESS_BLUETOOTH);
}
});
Dialog alertDialog = builder.create();
alertDialog.setCanceledOnTouchOutside(false);
alertDialog.show();
return false;
}
}
return true;
}
private static boolean requestLocationServicePermission(final Fragment fragment) {
LocationManager locationManager = (LocationManager) fragment.getActivity().getSystemService(LOCATION_SERVICE);
if (!(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER))) {
Timber.d("No GPS or Network location service is enabled, ask user for permission");
AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getContext());
builder.setTitle(R.string.permission_bluetooth_info_title);
builder.setIcon(R.drawable.ic_preferences_about);
builder.setMessage(R.string.permission_location_service_info);
builder.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
// Show location settings when the user acknowledges the alert dialog
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
fragment.getActivity().startActivity(intent);
}
});
Dialog alertDialog = builder.create();
alertDialog.setCanceledOnTouchOutside(false);
alertDialog.show();
return false;
}
return true;
}
public static boolean requestReadPermission(final Fragment fragment) {
if (fragment.getContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
fragment.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_ACCESS_READ_STORAGE);
} else {
return true;
}
return false;
}
public static boolean requestWritePermission(final Fragment fragment) {
if (fragment.getContext().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
fragment.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_ACCESS_WRITE_STORAGE);
} else {
return true;
}
return false;
}
}