From d0c59a6d75694002b22c1b85f88d5936bdeb6122 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 27 Jun 2023 10:48:04 -0300 Subject: [PATCH 01/14] Target SDK 33 and ask for notification permission when creating account and when signing in --- bramble-android/build.gradle | 2 +- briar-android/build.gradle | 2 +- briar-android/src/main/AndroidManifest.xml | 1 + .../android/account/SetPasswordFragment.java | 23 +++++++++++++++++++ .../briar/android/login/PasswordFragment.java | 21 +++++++++++++++++ .../src/main/res/layout/info_view.xml | 2 +- 6 files changed, 48 insertions(+), 3 deletions(-) diff --git a/bramble-android/build.gradle b/bramble-android/build.gradle index cc6786f48..5ca4b8a51 100644 --- a/bramble-android/build.gradle +++ b/bramble-android/build.gradle @@ -12,7 +12,7 @@ android { defaultConfig { minSdkVersion 21 - targetSdkVersion 31 + targetSdkVersion 33 versionCode 10504 versionName "1.5.4" consumerProguardFiles 'proguard-rules.txt' diff --git a/briar-android/build.gradle b/briar-android/build.gradle index 88dcd1b2b..fa172c88e 100644 --- a/briar-android/build.gradle +++ b/briar-android/build.gradle @@ -25,7 +25,7 @@ android { defaultConfig { minSdkVersion 21 - targetSdkVersion 31 + targetSdkVersion 33 versionCode 10504 versionName "1.5.4" applicationId "org.briarproject.briar.android" diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml index fd765c9f4..873971ae8 100644 --- a/briar-android/src/main/AndroidManifest.xml +++ b/briar-android/src/main/AndroidManifest.xml @@ -30,6 +30,7 @@ android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" tools:ignore="ScopedStorage" /> + diff --git a/briar-android/src/main/java/org/briarproject/briar/android/account/SetPasswordFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/account/SetPasswordFragment.java index 9d0047570..601cb59ff 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/account/SetPasswordFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/account/SetPasswordFragment.java @@ -19,10 +19,17 @@ import org.briarproject.nullsafety.ParametersNotNullByDefault; import javax.annotation.Nullable; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts.RequestPermission; + +import static android.Manifest.permission.POST_NOTIFICATIONS; import static android.content.Context.INPUT_METHOD_SERVICE; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.os.Build.VERSION.SDK_INT; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE; +import static androidx.core.content.ContextCompat.checkSelfPermission; import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK; import static org.briarproject.briar.android.util.UiUtils.setError; @@ -38,6 +45,10 @@ public class SetPasswordFragment extends SetupFragment { private StrengthMeter strengthMeter; private Button nextButton; + private final ActivityResultLauncher requestPermissionLauncher = + registerForActivityResult(new RequestPermission(), isGranted -> + setPassword()); + public static SetPasswordFragment newInstance() { return new SetPasswordFragment(); } @@ -121,6 +132,18 @@ public class SetPasswordFragment extends SetupFragment { IBinder token = passwordEntry.getWindowToken(); Object o = requireContext().getSystemService(INPUT_METHOD_SERVICE); ((InputMethodManager) o).hideSoftInputFromWindow(token, 0); + if (SDK_INT >= 33 && + checkSelfPermission(requireContext(), POST_NOTIFICATIONS) != + PERMISSION_GRANTED) { + // this calls setPassword() when it returns + requestPermissionLauncher.launch(POST_NOTIFICATIONS); + } else { + setPassword(); + } + } + + private void setPassword() { viewModel.setPassword(passwordEntry.getText().toString()); } + } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordFragment.java index 30d224c0a..7f5640444 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordFragment.java @@ -22,13 +22,19 @@ import org.briarproject.nullsafety.ParametersNotNullByDefault; import javax.annotation.Nullable; import javax.inject.Inject; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts.RequestPermission; import androidx.appcompat.app.AlertDialog; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.ViewModelProvider; +import static android.Manifest.permission.POST_NOTIFICATIONS; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.os.Build.VERSION.SDK_INT; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE; +import static androidx.core.content.ContextCompat.checkSelfPermission; import static org.briarproject.bramble.api.crypto.DecryptionResult.KEY_STRENGTHENER_ERROR; import static org.briarproject.bramble.api.crypto.DecryptionResult.SUCCESS; import static org.briarproject.briar.android.login.LoginUtils.createKeyStrengthenerErrorDialog; @@ -52,6 +58,10 @@ public class PasswordFragment extends BaseFragment implements TextWatcher { private TextInputLayout input; private TextInputEditText password; + private final ActivityResultLauncher requestPermissionLauncher = + registerForActivityResult(new RequestPermission(), isGranted -> + validatePassword()); + @Override public void injectFragment(ActivityComponent component) { component.inject(this); @@ -109,6 +119,17 @@ public class PasswordFragment extends BaseFragment implements TextWatcher { hideSoftKeyboard(password); signInButton.setVisibility(INVISIBLE); progress.setVisibility(VISIBLE); + if (SDK_INT >= 33 && + checkSelfPermission(requireContext(), POST_NOTIFICATIONS) != + PERMISSION_GRANTED) { + // this calls validatePassword() when it returns + requestPermissionLauncher.launch(POST_NOTIFICATIONS); + } else { + validatePassword(); + } + } + + private void validatePassword() { viewModel.validatePassword(password.getText().toString()); } diff --git a/briar-android/src/main/res/layout/info_view.xml b/briar-android/src/main/res/layout/info_view.xml index c7cf40f7b..8a884a4d8 100644 --- a/briar-android/src/main/res/layout/info_view.xml +++ b/briar-android/src/main/res/layout/info_view.xml @@ -13,10 +13,10 @@ android:layout_margin="@dimen/margin_medium" android:contentDescription="@string/info" android:drawablePadding="@dimen/margin_medium" - android:drawableTint="?attr/colorControlNormal" android:gravity="center_vertical" app:drawableLeftCompat="@drawable/ic_info_dark" app:drawableStartCompat="@drawable/ic_info_dark" + app:drawableTint="?attr/colorControlNormal" tools:text="Did you know that if you took all the veins out of your body and laid them out end to end, you would die?" /> \ No newline at end of file From fdb429ab7aebf7b07d6ea49264dce63f0ac2e262 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 27 Jun 2023 11:40:33 -0300 Subject: [PATCH 02/14] Ask for NEARBY_WIFI_DEVICES permission on SDK 33 and up --- briar-android/src/main/AndroidManifest.xml | 7 +- .../android/hotspot/ConditionManager29.java | 2 +- .../android/hotspot/ConditionManager33.java | 139 ++++++++++++++++++ .../android/hotspot/HotspotIntroFragment.java | 4 +- briar-android/src/main/res/values/strings.xml | 3 + 5 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml index 873971ae8..04fa06497 100644 --- a/briar-android/src/main/AndroidManifest.xml +++ b/briar-android/src/main/AndroidManifest.xml @@ -19,6 +19,10 @@ + @@ -32,7 +36,8 @@ tools:ignore="ScopedStorage" /> - + diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java index 64e399605..d243dd320 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java @@ -28,7 +28,7 @@ import static org.briarproject.briar.android.util.PermissionUtils.showLocationDi /** * This class ensures that the conditions to open a hotspot are fulfilled on - * API levels >= 29. + * API levels >= 29 and < 33. *

* As soon as {@link #checkAndRequestConditions()} returns true, * all conditions are fulfilled. diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java new file mode 100644 index 000000000..13a95aa84 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java @@ -0,0 +1,139 @@ +package org.briarproject.briar.android.hotspot; + +import android.content.Intent; +import android.provider.Settings; + +import org.briarproject.briar.R; +import org.briarproject.briar.android.util.Permission; +import org.briarproject.briar.android.util.PermissionUtils; + +import java.util.logging.Logger; + +import androidx.activity.result.ActivityResultCaller; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts.RequestPermission; +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.core.util.Consumer; + +import static android.Manifest.permission.NEARBY_WIFI_DEVICES; +import static androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale; +import static java.lang.Boolean.TRUE; +import static java.util.logging.Level.INFO; +import static java.util.logging.Logger.getLogger; + +/** + * This class ensures that the conditions to open a hotspot are fulfilled on + * API levels >= 33. + *

+ * As soon as {@link #checkAndRequestConditions()} returns true, + * all conditions are fulfilled. + */ +@RequiresApi(33) +class ConditionManager33 extends AbstractConditionManager { + + private static final Logger LOG = + getLogger(ConditionManager33.class.getName()); + + private Permission nearbyWifiPermission = Permission.UNKNOWN; + + private final ActivityResultLauncher nearbyWifiRequest; + private final ActivityResultLauncher wifiRequest; + + ConditionManager33(ActivityResultCaller arc, + Consumer permissionUpdateCallback) { + super(permissionUpdateCallback); + // permissionUpdateCallback receives false if permissions were denied + nearbyWifiRequest = arc.registerForActivityResult( + new RequestPermission(), granted -> { + onRequestPermissionResult(granted); + permissionUpdateCallback.accept(TRUE.equals(granted)); + }); + wifiRequest = arc.registerForActivityResult( + new StartActivityForResult(), + result -> permissionUpdateCallback + .accept(wifiManager.isWifiEnabled()) + ); + } + + @Override + void onStart() { + nearbyWifiPermission = Permission.UNKNOWN; + } + + private boolean areEssentialPermissionsGranted() { + boolean isWifiEnabled = wifiManager.isWifiEnabled(); + if (LOG.isLoggable(INFO)) { + LOG.info(String.format("areEssentialPermissionsGranted(): " + + "nearbyWifiPermission? %s, " + + "wifiManager.isWifiEnabled()? %b", + nearbyWifiPermission, isWifiEnabled)); + } + return nearbyWifiPermission == Permission.GRANTED && isWifiEnabled; + } + + @Override + boolean checkAndRequestConditions() { + if (areEssentialPermissionsGranted()) return true; + + if (nearbyWifiPermission == Permission.UNKNOWN) { + requestPermissions(); + return false; + } + + // If the location permission has been permanently denied, ask the + // user to change the setting + if (nearbyWifiPermission == Permission.PERMANENTLY_DENIED) { + PermissionUtils.showDenialDialog(ctx, + R.string.permission_nearby_devices_title, + R.string.permission_hotspot_nearby_wifi_denied_body, + () -> permissionUpdateCallback.accept(false)); + return false; + } + + // Should we show the rationale for location permission? + if (nearbyWifiPermission == Permission.SHOW_RATIONALE) { + showRationale(ctx, + R.string.permission_location_title, + R.string.permission_hotspot_nearby_wifi_request_body, + this::requestPermissions, + () -> permissionUpdateCallback.accept(false)); + return false; + } + + // If Wifi is not enabled, we show the rationale for enabling Wifi? + if (!wifiManager.isWifiEnabled()) { + showRationale(ctx, R.string.wifi_settings_title, + R.string.wifi_settings_request_enable_body, + this::requestEnableWiFi, + () -> permissionUpdateCallback.accept(false)); + return false; + } + + // we shouldn't usually reach this point, but if we do, return false + // anyway to force a recheck. Maybe some condition changed in the + // meantime. + return false; + } + + private void onRequestPermissionResult(@Nullable Boolean granted) { + if (granted != null && granted) { + nearbyWifiPermission = Permission.GRANTED; + } else if (shouldShowRequestPermissionRationale(ctx, + NEARBY_WIFI_DEVICES)) { + nearbyWifiPermission = Permission.SHOW_RATIONALE; + } else { + nearbyWifiPermission = Permission.PERMANENTLY_DENIED; + } + } + + private void requestPermissions() { + nearbyWifiRequest.launch(NEARBY_WIFI_DEVICES); + } + + private void requestEnableWiFi() { + wifiRequest.launch(new Intent(Settings.Panel.ACTION_WIFI)); + } + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java index c7e9bcd30..fbce088d4 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java @@ -50,7 +50,9 @@ public class HotspotIntroFragment extends Fragment { private final AbstractConditionManager conditionManager = SDK_INT < 29 ? new ConditionManager(this, this::onPermissionUpdate) : - new ConditionManager29(this, this::onPermissionUpdate); + SDK_INT >= 33 ? + new ConditionManager33(this, this::onPermissionUpdate) : + new ConditionManager29(this, this::onPermissionUpdate); @Override public void onAttach(Context context) { diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index c108f88d5..4719ed5f2 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -789,6 +789,7 @@ Camera permission To scan the QR code, Briar needs access to the camera. Location permission + Nearby devices permission To discover Bluetooth devices, Briar needs permission to access your location.\n\nBriar does not store your location or share it with anyone. Camera and location To scan the QR code, Briar needs access to the camera.\n\nTo discover Bluetooth devices, Briar needs permission to access your location.\n\nBriar does not store your location or share it with anyone. @@ -833,6 +834,8 @@ To create a Wi-Fi hotspot, Briar needs permission to access your precise location.\n\nBriar does not store your location or share it with anyone. You have denied access to your location, but Briar needs this permission to create a Wi-Fi hotspot.\n\nPlease consider granting access. You have denied access to your precise location, but Briar needs this permission to create a Wi-Fi hotspot.\n\nPlease consider granting access. + To create a Wi-Fi hotspot, Briar needs permission to access nearby devices. + You have denied access to nearby devices, but Briar needs this permission to create a Wi-Fi hotspot.\n\nPlease consider granting access. Wi-Fi setting To create a Wi-Fi hotspot, Briar needs to use Wi-Fi. Please enable it. From d19062e31976d3630656311bac86dad5244fdf06 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 27 Jun 2023 11:45:40 -0300 Subject: [PATCH 03/14] Don't disable hotspot start button after click to avoid issues when coming back to the screen after granting permissions. --- .../briarproject/briar/android/hotspot/HotspotIntroFragment.java | 1 - 1 file changed, 1 deletion(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java index fbce088d4..c07c85380 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java @@ -89,7 +89,6 @@ public class HotspotIntroFragment extends Fragment { } private void onButtonClick(View view) { - startButton.setEnabled(false); startHotspotIfConditionsFulfilled(); } From 03fc504f7d25d3859018af5827a220ee6050c212 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 28 Jun 2023 10:15:10 -0300 Subject: [PATCH 04/14] Log changes to LowPowerStandby in AndroidBatteryManager --- .../bramble/battery/AndroidBatteryManager.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/battery/AndroidBatteryManager.java b/bramble-android/src/main/java/org/briarproject/bramble/battery/AndroidBatteryManager.java index 0bd13b0b2..2f65a939a 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/battery/AndroidBatteryManager.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/battery/AndroidBatteryManager.java @@ -5,6 +5,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.os.PowerManager; import org.briarproject.bramble.api.battery.BatteryManager; import org.briarproject.bramble.api.battery.event.BatteryEvent; @@ -20,6 +21,8 @@ import static android.content.Intent.ACTION_BATTERY_CHANGED; import static android.content.Intent.ACTION_POWER_CONNECTED; import static android.content.Intent.ACTION_POWER_DISCONNECTED; import static android.os.BatteryManager.EXTRA_PLUGGED; +import static android.os.Build.VERSION.SDK_INT; +import static android.os.PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED; import static java.util.logging.Level.INFO; import static java.util.logging.Logger.getLogger; @@ -57,6 +60,9 @@ class AndroidBatteryManager implements BatteryManager, Service { IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_POWER_CONNECTED); filter.addAction(ACTION_POWER_DISCONNECTED); + if (SDK_INT >= 33) { + filter.addAction(ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED); + } appContext.registerReceiver(batteryReceiver, filter); } @@ -76,6 +82,13 @@ class AndroidBatteryManager implements BatteryManager, Service { eventBus.broadcast(new BatteryEvent(true)); else if (ACTION_POWER_DISCONNECTED.equals(action)) eventBus.broadcast(new BatteryEvent(false)); + else if (SDK_INT >= 33 && LOG.isLoggable(INFO) && + ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED.equals(action)) { + PowerManager powerManager = + ctx.getSystemService(PowerManager.class); + LOG.info("Low power standby now is: " + + powerManager.isLowPowerStandbyEnabled()); + } } } } From 2495b6f5c0964d2f1fa8c9395cc8e0241c0493ae Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 28 Jun 2023 10:20:34 -0300 Subject: [PATCH 05/14] Add LowPowerStandby stub to DozeWatchdogImpl --- .../briar/android/DozeWatchdogImpl.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/DozeWatchdogImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/DozeWatchdogImpl.java index e6cf8e227..b22214700 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/DozeWatchdogImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/DozeWatchdogImpl.java @@ -7,7 +7,6 @@ import android.content.IntentFilter; import android.os.PowerManager; import org.briarproject.bramble.api.lifecycle.Service; -import org.briarproject.bramble.api.lifecycle.ServiceException; import org.briarproject.briar.api.android.DozeWatchdog; import java.util.concurrent.atomic.AtomicBoolean; @@ -15,6 +14,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import static android.content.Context.POWER_SERVICE; import static android.os.Build.VERSION.SDK_INT; import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED; +import static android.os.PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED; class DozeWatchdogImpl implements DozeWatchdog, Service { @@ -32,14 +32,17 @@ class DozeWatchdogImpl implements DozeWatchdog, Service { } @Override - public void startService() throws ServiceException { + public void startService() { if (SDK_INT < 23) return; IntentFilter filter = new IntentFilter(ACTION_DEVICE_IDLE_MODE_CHANGED); + if (SDK_INT >= 33) { + filter.addAction(ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED); + } appContext.registerReceiver(receiver, filter); } @Override - public void stopService() throws ServiceException { + public void stopService() { if (SDK_INT < 23) return; appContext.unregisterReceiver(receiver); } @@ -49,9 +52,17 @@ class DozeWatchdogImpl implements DozeWatchdog, Service { @Override public void onReceive(Context context, Intent intent) { if (SDK_INT < 23) return; + String action = intent.getAction(); PowerManager pm = (PowerManager) appContext.getSystemService(POWER_SERVICE); - if (pm.isDeviceIdleMode()) dozed.set(true); + if (ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) { + if (pm.isDeviceIdleMode()) dozed.set(true); + } else if (ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED.equals( + action)) { + // pm.isLowPowerStandbyEnabled(); + // TODO what do we do with this now? Disable Tor? + // broadcast network disabled events? + } } } } From 45cda191e52ab02da1fdf441665e2b38dc5700fe Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 28 Jun 2023 10:24:43 -0300 Subject: [PATCH 06/14] Log changes to DeviceLightIdleMode in AndroidBatteryManager --- .../bramble/battery/AndroidBatteryManager.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/battery/AndroidBatteryManager.java b/bramble-android/src/main/java/org/briarproject/bramble/battery/AndroidBatteryManager.java index 2f65a939a..7b675a821 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/battery/AndroidBatteryManager.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/battery/AndroidBatteryManager.java @@ -22,6 +22,7 @@ import static android.content.Intent.ACTION_POWER_CONNECTED; import static android.content.Intent.ACTION_POWER_DISCONNECTED; import static android.os.BatteryManager.EXTRA_PLUGGED; import static android.os.Build.VERSION.SDK_INT; +import static android.os.PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED; import static android.os.PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED; import static java.util.logging.Level.INFO; import static java.util.logging.Logger.getLogger; @@ -62,6 +63,7 @@ class AndroidBatteryManager implements BatteryManager, Service { filter.addAction(ACTION_POWER_DISCONNECTED); if (SDK_INT >= 33) { filter.addAction(ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED); + filter.addAction(ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED); } appContext.registerReceiver(batteryReceiver, filter); } @@ -88,6 +90,12 @@ class AndroidBatteryManager implements BatteryManager, Service { ctx.getSystemService(PowerManager.class); LOG.info("Low power standby now is: " + powerManager.isLowPowerStandbyEnabled()); + } else if (SDK_INT >= 33 && LOG.isLoggable(INFO) && + ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED.equals(action)) { + PowerManager powerManager = + ctx.getSystemService(PowerManager.class); + LOG.info("Light idle mode now is: " + + powerManager.isDeviceLightIdleMode()); } } } From a34631d36cbcc31ab78069cfa8d85890f038f40c Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 28 Jun 2023 10:48:13 -0300 Subject: [PATCH 07/14] Catch ActivityNotFoundException in places where we launch external intents --- .../briar/android/account/DozeFragment.java | 10 +++++++++- .../android/account/HuaweiProtectedAppsView.java | 11 ++++++++++- .../briar/android/account/SetupActivity.java | 8 ++++---- .../briar/android/account/UnlockActivity.java | 9 ++++++++- .../briar/android/account/XiaomiLockAppsView.java | 9 +++++---- .../briar/android/activity/BriarActivity.java | 13 ++++++++++++- .../fragment/ScreenFilterDialogFragment.java | 13 ++++++++++++- .../briar/android/hotspot/ConditionManager.java | 13 ++++++++++++- .../briar/android/hotspot/ConditionManager29.java | 13 ++++++++++++- .../briar/android/hotspot/ConditionManager33.java | 13 ++++++++++++- .../briar/android/hotspot/FallbackFragment.java | 10 +++++++++- .../briar/android/util/PermissionUtils.java | 11 ++++++++--- 12 files changed, 113 insertions(+), 20 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/account/DozeFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/account/DozeFragment.java index 1c22e8187..64c313941 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/account/DozeFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/account/DozeFragment.java @@ -1,6 +1,7 @@ package org.briarproject.briar.android.account; import android.annotation.SuppressLint; +import android.content.ActivityNotFoundException; import android.content.Intent; import android.os.Bundle; import android.view.LayoutInflater; @@ -8,6 +9,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.ProgressBar; +import android.widget.Toast; import org.briarproject.briar.R; import org.briarproject.briar.android.account.PowerView.OnCheckedChangedListener; @@ -18,6 +20,7 @@ import androidx.annotation.Nullable; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; +import static android.widget.Toast.LENGTH_LONG; import static org.briarproject.android.dontkillmelib.DozeUtils.getDozeWhitelistingIntent; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING; import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog; @@ -113,7 +116,12 @@ public class DozeFragment extends SetupFragment private void askForDozeWhitelisting() { if (getContext() == null) return; Intent i = getDozeWhitelistingIntent(getContext()); - startActivityForResult(i, REQUEST_DOZE_WHITELISTING); + try { + startActivityForResult(i, REQUEST_DOZE_WHITELISTING); + } catch (ActivityNotFoundException e) { + Toast.makeText(requireContext(), + R.string.error_start_activity, LENGTH_LONG).show(); + } } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/account/HuaweiProtectedAppsView.java b/briar-android/src/main/java/org/briarproject/briar/android/account/HuaweiProtectedAppsView.java index ec4b442b8..225ec1265 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/account/HuaweiProtectedAppsView.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/account/HuaweiProtectedAppsView.java @@ -1,8 +1,10 @@ package org.briarproject.briar.android.account; +import android.content.ActivityNotFoundException; import android.content.Context; import android.util.AttributeSet; +import android.widget.Toast; import org.briarproject.briar.R; import org.briarproject.nullsafety.NotNullByDefault; @@ -12,6 +14,7 @@ import javax.annotation.Nullable; import androidx.annotation.StringRes; import androidx.annotation.UiThread; +import static android.widget.Toast.LENGTH_LONG; import static org.briarproject.android.dontkillmelib.HuaweiUtils.getHuaweiProtectedAppsIntent; import static org.briarproject.android.dontkillmelib.HuaweiUtils.protectedAppsNeedsToBeShown; @@ -49,7 +52,13 @@ class HuaweiProtectedAppsView extends PowerView { @Override protected void onButtonClick() { - getContext().startActivity(getHuaweiProtectedAppsIntent()); + Context ctx = getContext(); + try { + ctx.startActivity(getHuaweiProtectedAppsIntent()); + } catch (ActivityNotFoundException e) { + Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG) + .show(); + } setChecked(true); } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/account/SetupActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupActivity.java index 55d04c238..c53bf9352 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/account/SetupActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupActivity.java @@ -36,7 +36,7 @@ public class SetupActivity extends BaseActivity @Inject ViewModelProvider.Factory viewModelFactory; - SetupViewModel viewModel; + private SetupViewModel viewModel; @Override public void injectActivity(ActivityComponent component) { @@ -71,16 +71,16 @@ public class SetupActivity extends BaseActivity } } - void showPasswordFragment() { + private void showPasswordFragment() { showNextFragment(SetPasswordFragment.newInstance()); } @TargetApi(23) - void showDozeFragment() { + private void showDozeFragment() { showNextFragment(DozeFragment.newInstance()); } - void showApp() { + private void showApp() { Intent i = new Intent(this, ENTRY_ACTIVITY); i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME | FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_CLEAR_TOP); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/account/UnlockActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/account/UnlockActivity.java index 65c357949..297b22469 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/account/UnlockActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/account/UnlockActivity.java @@ -1,6 +1,7 @@ package org.briarproject.briar.android.account; import android.app.KeyguardManager; +import android.content.ActivityNotFoundException; import android.content.Intent; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback; @@ -28,6 +29,7 @@ import static android.hardware.biometrics.BiometricPrompt.BIOMETRIC_ERROR_CANCEL import static android.hardware.biometrics.BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED; import static android.os.Build.VERSION.SDK_INT; import static android.view.View.INVISIBLE; +import static android.widget.Toast.LENGTH_LONG; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_KEYGUARD_UNLOCK; import static org.briarproject.briar.android.util.UiUtils.hasKeyguardLock; import static org.briarproject.briar.android.util.UiUtils.hasUsableFingerprint; @@ -191,7 +193,12 @@ public class UnlockActivity extends BaseActivity { unlock(); } else { keyguardShown = true; - startActivityForResult(intent, REQUEST_KEYGUARD_UNLOCK); + try { + startActivityForResult(intent, REQUEST_KEYGUARD_UNLOCK); + } catch (ActivityNotFoundException e) { + Toast.makeText(this, R.string.error_start_activity, LENGTH_LONG) + .show(); + } overridePendingTransition(0, 0); } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/account/XiaomiLockAppsView.java b/briar-android/src/main/java/org/briarproject/briar/android/account/XiaomiLockAppsView.java index d2af11a90..1b268dd89 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/account/XiaomiLockAppsView.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/account/XiaomiLockAppsView.java @@ -1,5 +1,6 @@ package org.briarproject.briar.android.account; +import android.content.ActivityNotFoundException; import android.content.Context; import android.util.AttributeSet; import android.widget.Toast; @@ -60,12 +61,12 @@ class XiaomiLockAppsView extends PowerView { getContext().startActivity(getXiaomiLockAppsIntent()); setChecked(true); return; - } catch (SecurityException e) { + } catch (SecurityException | ActivityNotFoundException e) { logException(LOG, WARNING, e); + Toast.makeText(getContext(), + R.string.dnkm_xiaomi_lock_apps_error_toast, + LENGTH_LONG).show(); } - Toast.makeText(getContext(), - R.string.dnkm_xiaomi_lock_apps_error_toast, - LENGTH_LONG).show(); // Let the user continue with setup setChecked(true); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java index 1370c5f9c..ed349038b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java @@ -1,9 +1,11 @@ package org.briarproject.briar.android.activity; +import android.content.ActivityNotFoundException; import android.content.Intent; import android.transition.Transition; import android.view.Window; import android.widget.CheckBox; +import android.widget.Toast; import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager; import org.briarproject.bramble.api.system.Wakeful; @@ -34,9 +36,12 @@ import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; import static android.os.Build.VERSION.SDK_INT; +import static android.widget.Toast.LENGTH_LONG; import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; import static org.briarproject.android.dontkillmelib.DozeUtils.getDozeWhitelistingIntent; +import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PASSWORD; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_UNLOCK; @@ -179,7 +184,13 @@ public abstract class BriarActivity extends BaseActivity { b.setPositiveButton(R.string.fix, (dialog, which) -> { Intent i = getDozeWhitelistingIntent(BriarActivity.this); - startActivityForResult(i, REQUEST_DOZE_WHITELISTING); + try { + startActivityForResult(i, REQUEST_DOZE_WHITELISTING); + } catch (ActivityNotFoundException e) { + logException(LOG, WARNING, e); + Toast.makeText(this, R.string.error_start_activity, + LENGTH_LONG).show(); + } dialog.dismiss(); }); b.setNegativeButton(R.string.cancel, diff --git a/briar-android/src/main/java/org/briarproject/briar/android/fragment/ScreenFilterDialogFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/fragment/ScreenFilterDialogFragment.java index 923f0f775..9b338009a 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/fragment/ScreenFilterDialogFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/fragment/ScreenFilterDialogFragment.java @@ -3,6 +3,7 @@ package org.briarproject.briar.android.fragment; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -12,6 +13,7 @@ import android.view.LayoutInflater; import android.view.View; import android.widget.CheckBox; import android.widget.TextView; +import android.widget.Toast; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.BaseActivity; @@ -19,6 +21,7 @@ import org.briarproject.briar.api.android.ScreenFilterMonitor; import org.briarproject.briar.api.android.ScreenFilterMonitor.AppDetails; import org.briarproject.nullsafety.MethodsNotNullByDefault; import org.briarproject.nullsafety.ParametersNotNullByDefault; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collection; @@ -32,6 +35,7 @@ import androidx.fragment.app.DialogFragment; import static android.os.Build.VERSION.SDK_INT; import static android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION; import static android.view.View.GONE; +import static android.widget.Toast.LENGTH_LONG; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -68,6 +72,7 @@ public class ScreenFilterDialogFragment extends DialogFragment { ((BaseActivity) requireActivity()).getActivityComponent().inject(this); } + @NotNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { Activity activity = getActivity(); @@ -98,7 +103,13 @@ public class ScreenFilterDialogFragment extends DialogFragment { builder.setNeutralButton(R.string.screen_filter_review_apps, (dialog, which) -> { Intent i = new Intent(ACTION_MANAGE_OVERLAY_PERMISSION); - startActivity(i); + try { + startActivity(i); + } catch (ActivityNotFoundException e) { + Toast.makeText(requireContext(), + R.string.error_start_activity, LENGTH_LONG) + .show(); + } }); } builder.setPositiveButton(R.string.continue_button, (dialog, which) -> { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager.java index 95c0d57fe..6c0312244 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager.java @@ -1,7 +1,9 @@ package org.briarproject.briar.android.hotspot; +import android.content.ActivityNotFoundException; import android.content.Intent; import android.provider.Settings; +import android.widget.Toast; import org.briarproject.briar.R; @@ -12,8 +14,11 @@ import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; import androidx.core.util.Consumer; +import static android.widget.Toast.LENGTH_LONG; import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.util.LogUtils.logException; /** * This class ensures that the conditions to open a hotspot are fulfilled on @@ -77,7 +82,13 @@ class ConditionManager extends AbstractConditionManager { } private void requestEnableWiFi() { - wifiRequest.launch(new Intent(Settings.ACTION_WIFI_SETTINGS)); + try { + wifiRequest.launch(new Intent(Settings.ACTION_WIFI_SETTINGS)); + } catch (ActivityNotFoundException e) { + logException(LOG, WARNING, e); + Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG) + .show(); + } } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java index d243dd320..fc5318cc8 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java @@ -1,7 +1,9 @@ package org.briarproject.briar.android.hotspot; +import android.content.ActivityNotFoundException; import android.content.Intent; import android.provider.Settings; +import android.widget.Toast; import org.briarproject.briar.R; import org.briarproject.briar.android.util.Permission; @@ -19,10 +21,13 @@ import androidx.core.util.Consumer; import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.os.Build.VERSION.SDK_INT; +import static android.widget.Toast.LENGTH_LONG; import static androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale; import static java.lang.Boolean.TRUE; import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.briar.android.util.PermissionUtils.isLocationEnabledForWiFi; import static org.briarproject.briar.android.util.PermissionUtils.showLocationDialog; @@ -147,7 +152,13 @@ class ConditionManager29 extends AbstractConditionManager { } private void requestEnableWiFi() { - wifiRequest.launch(new Intent(Settings.Panel.ACTION_WIFI)); + try { + wifiRequest.launch(new Intent(Settings.Panel.ACTION_WIFI)); + } catch (ActivityNotFoundException e) { + logException(LOG, WARNING, e); + Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG) + .show(); + } } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java index 13a95aa84..4f4d8b23b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java @@ -1,7 +1,9 @@ package org.briarproject.briar.android.hotspot; +import android.content.ActivityNotFoundException; import android.content.Intent; import android.provider.Settings; +import android.widget.Toast; import org.briarproject.briar.R; import org.briarproject.briar.android.util.Permission; @@ -18,10 +20,13 @@ import androidx.annotation.RequiresApi; import androidx.core.util.Consumer; import static android.Manifest.permission.NEARBY_WIFI_DEVICES; +import static android.widget.Toast.LENGTH_LONG; import static androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale; import static java.lang.Boolean.TRUE; import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.util.LogUtils.logException; /** * This class ensures that the conditions to open a hotspot are fulfilled on @@ -133,7 +138,13 @@ class ConditionManager33 extends AbstractConditionManager { } private void requestEnableWiFi() { - wifiRequest.launch(new Intent(Settings.Panel.ACTION_WIFI)); + try { + wifiRequest.launch(new Intent(Settings.Panel.ACTION_WIFI)); + } catch (ActivityNotFoundException e) { + logException(LOG, WARNING, e); + Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG) + .show(); + } } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/FallbackFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/FallbackFragment.java index efc81a9f6..00dfcaa01 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/FallbackFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/FallbackFragment.java @@ -1,5 +1,6 @@ package org.briarproject.briar.android.hotspot; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.net.Uri; @@ -9,6 +10,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.ProgressBar; +import android.widget.Toast; import org.briarproject.briar.R; import org.briarproject.briar.android.fragment.BaseFragment; @@ -28,6 +30,7 @@ import static android.content.Intent.EXTRA_STREAM; import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; +import static android.widget.Toast.LENGTH_LONG; import static androidx.transition.TransitionManager.beginDelayedTransition; import static org.briarproject.briar.android.AppModule.getAndroidComponent; import static org.briarproject.briar.android.hotspot.HotspotViewModel.getApkFileName; @@ -102,7 +105,12 @@ public class FallbackFragment extends BaseFragment { i.putExtra(EXTRA_STREAM, uri); i.setType("*/*"); // gives us all sharing options i.addFlags(FLAG_GRANT_READ_URI_PERMISSION); - startActivity(Intent.createChooser(i, null)); + try { + startActivity(Intent.createChooser(i, null)); + } catch (ActivityNotFoundException e) { + Toast.makeText(requireContext(), R.string.error_start_activity, + LENGTH_LONG).show(); + } } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/PermissionUtils.java b/briar-android/src/main/java/org/briarproject/briar/android/util/PermissionUtils.java index fdad47615..ded32de32 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/util/PermissionUtils.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/util/PermissionUtils.java @@ -47,7 +47,7 @@ public class PermissionUtils { } } - public static boolean isPermissionGranted(Context ctx, String permission) { + private static boolean isPermissionGranted(Context ctx, String permission) { return checkSelfPermission(ctx, permission) == PERMISSION_GRANTED; } @@ -68,7 +68,7 @@ public class PermissionUtils { gotPermission(ctx, grantedMap, BLUETOOTH_SCAN); } - public static DialogInterface.OnClickListener getGoToSettingsListener( + private static DialogInterface.OnClickListener getGoToSettingsListener( Context context) { return (dialog, which) -> { Intent i = new Intent(); @@ -76,7 +76,12 @@ public class PermissionUtils { i.addCategory(CATEGORY_DEFAULT); i.setData(Uri.parse("package:" + APPLICATION_ID)); i.addFlags(FLAG_ACTIVITY_NEW_TASK); - context.startActivity(i); + try { + context.startActivity(i); + } catch (ActivityNotFoundException e) { + Toast.makeText(context, R.string.error_start_activity, + LENGTH_LONG).show(); + } }; } From fa216ffc6f2a0a3c35705d3c1130189cbf4e277d Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 28 Jun 2023 14:40:31 -0300 Subject: [PATCH 08/14] Move requestEnableWiFi() into AbstractConditionManager --- .../hotspot/AbstractConditionManager.java | 26 ++++++++++++++-- .../android/hotspot/ConditionManager.java | 31 +++---------------- .../android/hotspot/ConditionManager29.java | 28 +++-------------- .../android/hotspot/ConditionManager33.java | 28 +++-------------- .../android/hotspot/HotspotIntroFragment.java | 2 +- 5 files changed, 40 insertions(+), 75 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/AbstractConditionManager.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/AbstractConditionManager.java index edfef7303..435a486a8 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/AbstractConditionManager.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/AbstractConditionManager.java @@ -1,21 +1,27 @@ package org.briarproject.briar.android.hotspot; +import android.content.ActivityNotFoundException; import android.content.Context; +import android.content.Intent; import android.net.wifi.WifiManager; +import android.widget.Toast; import org.briarproject.briar.R; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.StringRes; import androidx.appcompat.app.AlertDialog; import androidx.core.util.Consumer; import androidx.fragment.app.FragmentActivity; import static android.content.Context.WIFI_SERVICE; +import static android.widget.Toast.LENGTH_LONG; /** * Abstract base class for the ConditionManagers that ensure that the conditions * to open a hotspot are fulfilled. There are different extensions of this for - * API levels lower than 29 and 29+. + * API levels lower than 29, 29+ and 33+. */ abstract class AbstractConditionManager { @@ -28,6 +34,7 @@ abstract class AbstractConditionManager { final Consumer permissionUpdateCallback; protected FragmentActivity ctx; WifiManager wifiManager; + private ActivityResultLauncher wifiRequest; AbstractConditionManager(Consumer permissionUpdateCallback) { this.permissionUpdateCallback = permissionUpdateCallback; @@ -38,8 +45,12 @@ abstract class AbstractConditionManager { */ void init(FragmentActivity ctx) { this.ctx = ctx; - this.wifiManager = (WifiManager) ctx.getApplicationContext() + wifiManager = (WifiManager) ctx.getApplicationContext() .getSystemService(WIFI_SERVICE); + wifiRequest = ctx.registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + result -> permissionUpdateCallback + .accept(wifiManager.isWifiEnabled())); } /** @@ -57,6 +68,8 @@ abstract class AbstractConditionManager { */ abstract boolean checkAndRequestConditions(); + abstract String getWifiSettingsAction(); + void showRationale(Context ctx, @StringRes int title, @StringRes int body, Runnable onContinueClicked, Runnable onDismiss) { @@ -69,4 +82,13 @@ abstract class AbstractConditionManager { builder.show(); } + void requestEnableWiFi() { + try { + wifiRequest.launch(new Intent(getWifiSettingsAction())); + } catch (ActivityNotFoundException e) { + Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG) + .show(); + } + } + } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager.java index 6c0312244..251310c50 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager.java @@ -1,24 +1,15 @@ package org.briarproject.briar.android.hotspot; -import android.content.ActivityNotFoundException; -import android.content.Intent; import android.provider.Settings; -import android.widget.Toast; import org.briarproject.briar.R; import java.util.logging.Logger; -import androidx.activity.result.ActivityResultCaller; -import androidx.activity.result.ActivityResultLauncher; -import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; import androidx.core.util.Consumer; -import static android.widget.Toast.LENGTH_LONG; import static java.util.logging.Level.INFO; -import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.util.LogUtils.logException; /** * This class ensures that the conditions to open a hotspot are fulfilled on @@ -32,15 +23,8 @@ class ConditionManager extends AbstractConditionManager { private static final Logger LOG = getLogger(ConditionManager.class.getName()); - private final ActivityResultLauncher wifiRequest; - - ConditionManager(ActivityResultCaller arc, - Consumer permissionUpdateCallback) { - super(permissionUpdateCallback); - wifiRequest = arc.registerForActivityResult( - new StartActivityForResult(), - result -> permissionUpdateCallback - .accept(wifiManager.isWifiEnabled())); + ConditionManager(Consumer permissionUpdateCallback) { + super( permissionUpdateCallback); } @Override @@ -81,14 +65,9 @@ class ConditionManager extends AbstractConditionManager { return false; } - private void requestEnableWiFi() { - try { - wifiRequest.launch(new Intent(Settings.ACTION_WIFI_SETTINGS)); - } catch (ActivityNotFoundException e) { - logException(LOG, WARNING, e); - Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG) - .show(); - } + @Override + String getWifiSettingsAction() { + return Settings.ACTION_WIFI_SETTINGS; } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java index fc5318cc8..381d0a694 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java @@ -1,9 +1,6 @@ package org.briarproject.briar.android.hotspot; -import android.content.ActivityNotFoundException; -import android.content.Intent; import android.provider.Settings; -import android.widget.Toast; import org.briarproject.briar.R; import org.briarproject.briar.android.util.Permission; @@ -14,20 +11,16 @@ import java.util.logging.Logger; import androidx.activity.result.ActivityResultCaller; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts.RequestPermission; -import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.core.util.Consumer; import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.os.Build.VERSION.SDK_INT; -import static android.widget.Toast.LENGTH_LONG; import static androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale; import static java.lang.Boolean.TRUE; import static java.util.logging.Level.INFO; -import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.briar.android.util.PermissionUtils.isLocationEnabledForWiFi; import static org.briarproject.briar.android.util.PermissionUtils.showLocationDialog; @@ -47,7 +40,6 @@ class ConditionManager29 extends AbstractConditionManager { private Permission locationPermission = Permission.UNKNOWN; private final ActivityResultLauncher locationRequest; - private final ActivityResultLauncher wifiRequest; ConditionManager29(ActivityResultCaller arc, Consumer permissionUpdateCallback) { @@ -58,11 +50,6 @@ class ConditionManager29 extends AbstractConditionManager { onRequestPermissionResult(granted); permissionUpdateCallback.accept(TRUE.equals(granted)); }); - wifiRequest = arc.registerForActivityResult( - new StartActivityForResult(), - result -> permissionUpdateCallback - .accept(wifiManager.isWifiEnabled()) - ); } @Override @@ -136,6 +123,11 @@ class ConditionManager29 extends AbstractConditionManager { return false; } + @Override + String getWifiSettingsAction() { + return Settings.Panel.ACTION_WIFI; + } + private void onRequestPermissionResult(@Nullable Boolean granted) { if (granted != null && granted) { locationPermission = Permission.GRANTED; @@ -151,14 +143,4 @@ class ConditionManager29 extends AbstractConditionManager { locationRequest.launch(ACCESS_FINE_LOCATION); } - private void requestEnableWiFi() { - try { - wifiRequest.launch(new Intent(Settings.Panel.ACTION_WIFI)); - } catch (ActivityNotFoundException e) { - logException(LOG, WARNING, e); - Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG) - .show(); - } - } - } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java index 4f4d8b23b..f33427338 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java @@ -1,9 +1,6 @@ package org.briarproject.briar.android.hotspot; -import android.content.ActivityNotFoundException; -import android.content.Intent; import android.provider.Settings; -import android.widget.Toast; import org.briarproject.briar.R; import org.briarproject.briar.android.util.Permission; @@ -14,19 +11,15 @@ import java.util.logging.Logger; import androidx.activity.result.ActivityResultCaller; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts.RequestPermission; -import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.core.util.Consumer; import static android.Manifest.permission.NEARBY_WIFI_DEVICES; -import static android.widget.Toast.LENGTH_LONG; import static androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale; import static java.lang.Boolean.TRUE; import static java.util.logging.Level.INFO; -import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.util.LogUtils.logException; /** * This class ensures that the conditions to open a hotspot are fulfilled on @@ -44,7 +37,6 @@ class ConditionManager33 extends AbstractConditionManager { private Permission nearbyWifiPermission = Permission.UNKNOWN; private final ActivityResultLauncher nearbyWifiRequest; - private final ActivityResultLauncher wifiRequest; ConditionManager33(ActivityResultCaller arc, Consumer permissionUpdateCallback) { @@ -55,11 +47,6 @@ class ConditionManager33 extends AbstractConditionManager { onRequestPermissionResult(granted); permissionUpdateCallback.accept(TRUE.equals(granted)); }); - wifiRequest = arc.registerForActivityResult( - new StartActivityForResult(), - result -> permissionUpdateCallback - .accept(wifiManager.isWifiEnabled()) - ); } @Override @@ -122,6 +109,11 @@ class ConditionManager33 extends AbstractConditionManager { return false; } + @Override + String getWifiSettingsAction() { + return Settings.Panel.ACTION_WIFI; + } + private void onRequestPermissionResult(@Nullable Boolean granted) { if (granted != null && granted) { nearbyWifiPermission = Permission.GRANTED; @@ -137,14 +129,4 @@ class ConditionManager33 extends AbstractConditionManager { nearbyWifiRequest.launch(NEARBY_WIFI_DEVICES); } - private void requestEnableWiFi() { - try { - wifiRequest.launch(new Intent(Settings.Panel.ACTION_WIFI)); - } catch (ActivityNotFoundException e) { - logException(LOG, WARNING, e); - Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG) - .show(); - } - } - } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java index c07c85380..db8e1cf22 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java @@ -49,7 +49,7 @@ public class HotspotIntroFragment extends Fragment { private TextView progressTextView; private final AbstractConditionManager conditionManager = SDK_INT < 29 ? - new ConditionManager(this, this::onPermissionUpdate) : + new ConditionManager(this::onPermissionUpdate) : SDK_INT >= 33 ? new ConditionManager33(this, this::onPermissionUpdate) : new ConditionManager29(this, this::onPermissionUpdate); From 3d237a91043b3f5936ac4bf204a5962f4f1618ea Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 28 Jun 2023 14:49:36 -0300 Subject: [PATCH 09/14] Introduce tryToStartActivity() helper method --- .../account/HuaweiProtectedAppsView.java | 12 ++---------- .../fragment/ScreenFilterDialogFragment.java | 12 ++---------- .../android/hotspot/FallbackFragment.java | 11 ++--------- .../android/reporting/ReportFormFragment.java | 13 ++----------- .../briar/android/settings/AboutFragment.java | 18 ++++-------------- .../android/settings/SettingsFragment.java | 12 +++--------- .../briar/android/util/PermissionUtils.java | 18 +++--------------- .../briar/android/util/UiUtils.java | 9 +++++++++ 8 files changed, 27 insertions(+), 78 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/account/HuaweiProtectedAppsView.java b/briar-android/src/main/java/org/briarproject/briar/android/account/HuaweiProtectedAppsView.java index 225ec1265..31a3fc79f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/account/HuaweiProtectedAppsView.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/account/HuaweiProtectedAppsView.java @@ -1,10 +1,8 @@ package org.briarproject.briar.android.account; -import android.content.ActivityNotFoundException; import android.content.Context; import android.util.AttributeSet; -import android.widget.Toast; import org.briarproject.briar.R; import org.briarproject.nullsafety.NotNullByDefault; @@ -14,9 +12,9 @@ import javax.annotation.Nullable; import androidx.annotation.StringRes; import androidx.annotation.UiThread; -import static android.widget.Toast.LENGTH_LONG; import static org.briarproject.android.dontkillmelib.HuaweiUtils.getHuaweiProtectedAppsIntent; import static org.briarproject.android.dontkillmelib.HuaweiUtils.protectedAppsNeedsToBeShown; +import static org.briarproject.briar.android.util.UiUtils.tryToStartActivity; @UiThread @NotNullByDefault @@ -52,13 +50,7 @@ class HuaweiProtectedAppsView extends PowerView { @Override protected void onButtonClick() { - Context ctx = getContext(); - try { - ctx.startActivity(getHuaweiProtectedAppsIntent()); - } catch (ActivityNotFoundException e) { - Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG) - .show(); - } + tryToStartActivity(getContext(), getHuaweiProtectedAppsIntent()); setChecked(true); } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/fragment/ScreenFilterDialogFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/fragment/ScreenFilterDialogFragment.java index 9b338009a..2e2ed6bf2 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/fragment/ScreenFilterDialogFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/fragment/ScreenFilterDialogFragment.java @@ -3,7 +3,6 @@ package org.briarproject.briar.android.fragment; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; -import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -13,7 +12,6 @@ import android.view.LayoutInflater; import android.view.View; import android.widget.CheckBox; import android.widget.TextView; -import android.widget.Toast; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.BaseActivity; @@ -35,7 +33,7 @@ import androidx.fragment.app.DialogFragment; import static android.os.Build.VERSION.SDK_INT; import static android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION; import static android.view.View.GONE; -import static android.widget.Toast.LENGTH_LONG; +import static org.briarproject.briar.android.util.UiUtils.tryToStartActivity; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -103,13 +101,7 @@ public class ScreenFilterDialogFragment extends DialogFragment { builder.setNeutralButton(R.string.screen_filter_review_apps, (dialog, which) -> { Intent i = new Intent(ACTION_MANAGE_OVERLAY_PERMISSION); - try { - startActivity(i); - } catch (ActivityNotFoundException e) { - Toast.makeText(requireContext(), - R.string.error_start_activity, LENGTH_LONG) - .show(); - } + tryToStartActivity(requireActivity(), i); }); } builder.setPositiveButton(R.string.continue_button, (dialog, which) -> { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/FallbackFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/FallbackFragment.java index 00dfcaa01..394012f8c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/FallbackFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/FallbackFragment.java @@ -1,6 +1,5 @@ package org.briarproject.briar.android.hotspot; -import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.net.Uri; @@ -10,7 +9,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.ProgressBar; -import android.widget.Toast; import org.briarproject.briar.R; import org.briarproject.briar.android.fragment.BaseFragment; @@ -30,10 +28,10 @@ import static android.content.Intent.EXTRA_STREAM; import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; -import static android.widget.Toast.LENGTH_LONG; import static androidx.transition.TransitionManager.beginDelayedTransition; import static org.briarproject.briar.android.AppModule.getAndroidComponent; import static org.briarproject.briar.android.hotspot.HotspotViewModel.getApkFileName; +import static org.briarproject.briar.android.util.UiUtils.tryToStartActivity; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -105,12 +103,7 @@ public class FallbackFragment extends BaseFragment { i.putExtra(EXTRA_STREAM, uri); i.setType("*/*"); // gives us all sharing options i.addFlags(FLAG_GRANT_READ_URI_PERMISSION); - try { - startActivity(Intent.createChooser(i, null)); - } catch (ActivityNotFoundException e) { - Toast.makeText(requireContext(), R.string.error_start_activity, - LENGTH_LONG).show(); - } + tryToStartActivity(requireActivity(), Intent.createChooser(i, null)); } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportFormFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportFormFragment.java index 8eff6d704..b915b815a 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportFormFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportFormFragment.java @@ -1,6 +1,5 @@ package org.briarproject.briar.android.reporting; -import android.content.ActivityNotFoundException; import android.content.Intent; import android.net.Uri; import android.os.Bundle; @@ -33,13 +32,11 @@ import androidx.recyclerview.widget.RecyclerView; import static android.view.View.GONE; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; -import static android.widget.Toast.LENGTH_LONG; import static android.widget.Toast.LENGTH_SHORT; import static java.util.Objects.requireNonNull; -import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.briar.android.util.UiUtils.onSingleLinkClick; +import static org.briarproject.briar.android.util.UiUtils.tryToStartActivity; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -180,13 +177,7 @@ public class ReportFormFragment extends BaseFragment { private void triggerPrivacyPolicy() { Intent i = new Intent(Intent.ACTION_VIEW); i.setData(Uri.parse("https://briarproject.org/privacy-policy/\\")); - try { - startActivity(i); - } catch (ActivityNotFoundException e) { - logException(LOG, WARNING, e); - Toast.makeText(requireContext(), - R.string.error_start_activity, LENGTH_LONG).show(); - } + tryToStartActivity(requireActivity(), i); } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/AboutFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/AboutFragment.java index 664e7f286..fff46763e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/settings/AboutFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/AboutFragment.java @@ -1,6 +1,5 @@ package org.briarproject.briar.android.settings; -import android.content.ActivityNotFoundException; import android.content.Intent; import android.net.Uri; import android.os.Bundle; @@ -8,7 +7,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import android.widget.Toast; import org.briarproject.briar.BuildConfig; import org.briarproject.briar.R; @@ -21,10 +19,9 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import static android.widget.Toast.LENGTH_LONG; -import static java.util.logging.Level.WARNING; +import static android.content.Intent.ACTION_VIEW; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.util.LogUtils.logException; +import static org.briarproject.briar.android.util.UiUtils.tryToStartActivity; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -85,16 +82,9 @@ public class AboutFragment extends Fragment { } private void goToUrl(String url) { - Intent i = new Intent(Intent.ACTION_VIEW); + Intent i = new Intent(ACTION_VIEW); i.setData(Uri.parse(url)); - try { - startActivity(i); - } catch (ActivityNotFoundException e) { - logException(LOG, WARNING, e); - Toast.makeText(requireContext(), - R.string.error_start_activity, LENGTH_LONG).show(); - } - + tryToStartActivity(requireActivity(), i); } } \ No newline at end of file diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java index 2d5ec5fc1..314c283cb 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java @@ -1,12 +1,10 @@ package org.briarproject.briar.android.settings; -import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; -import android.widget.Toast; import org.briarproject.briar.R; import org.briarproject.briar.android.mailbox.MailboxActivity; @@ -28,12 +26,12 @@ import androidx.preference.PreferenceGroup; import static android.content.Intent.ACTION_SEND; import static android.content.Intent.EXTRA_TEXT; -import static android.widget.Toast.LENGTH_LONG; import static java.util.Objects.requireNonNull; import static org.briarproject.briar.android.AppModule.getAndroidComponent; import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD; import static org.briarproject.briar.android.util.UiUtils.launchActivityToOpenFile; import static org.briarproject.briar.android.util.UiUtils.triggerFeedback; +import static org.briarproject.briar.android.util.UiUtils.tryToStartActivity; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -101,12 +99,8 @@ public class SettingsFragment extends PreferenceFragmentCompat { Intent sendIntent = new Intent(ACTION_SEND); sendIntent.putExtra(EXTRA_TEXT, text); sendIntent.setType("text/plain"); - try { - startActivity(Intent.createChooser(sendIntent, null)); - } catch (ActivityNotFoundException e) { - Toast.makeText(requireContext(), - R.string.error_start_activity, LENGTH_LONG).show(); - } + tryToStartActivity(requireActivity(), + Intent.createChooser(sendIntent, null)); return true; }); Preference prefFeedback = diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/PermissionUtils.java b/briar-android/src/main/java/org/briarproject/briar/android/util/PermissionUtils.java index ded32de32..d1c6432a8 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/util/PermissionUtils.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/util/PermissionUtils.java @@ -1,12 +1,10 @@ package org.briarproject.briar.android.util; -import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.location.LocationManager; import android.net.Uri; -import android.widget.Toast; import org.briarproject.briar.R; import org.briarproject.nullsafety.MethodsNotNullByDefault; @@ -29,10 +27,10 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Build.VERSION.SDK_INT; import static android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS; -import static android.widget.Toast.LENGTH_LONG; import static androidx.core.content.ContextCompat.checkSelfPermission; import static java.lang.Boolean.TRUE; import static org.briarproject.briar.BuildConfig.APPLICATION_ID; +import static org.briarproject.briar.android.util.UiUtils.tryToStartActivity; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -76,12 +74,7 @@ public class PermissionUtils { i.addCategory(CATEGORY_DEFAULT); i.setData(Uri.parse("package:" + APPLICATION_ID)); i.addFlags(FLAG_ACTIVITY_NEW_TASK); - try { - context.startActivity(i); - } catch (ActivityNotFoundException e) { - Toast.makeText(context, R.string.error_start_activity, - LENGTH_LONG).show(); - } + tryToStartActivity(context, i); }; } @@ -128,12 +121,7 @@ public class PermissionUtils { builder.setPositiveButton(R.string.permission_location_setting_button, (dialog, which) -> { Intent i = new Intent(ACTION_LOCATION_SOURCE_SETTINGS); - try { - ctx.startActivity(i); - } catch (ActivityNotFoundException e) { - Toast.makeText(ctx, R.string.error_start_activity, - LENGTH_LONG).show(); - } + tryToStartActivity(ctx, i); }); builder.show(); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java index 78a0e3ad2..c92d5829e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java @@ -157,6 +157,15 @@ public class UiUtils { ta.commit(); } + public static void tryToStartActivity(Context ctx, Intent intent) { + try { + ctx.startActivity(intent); + } catch (ActivityNotFoundException e) { + Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG) + .show(); + } + } + public static String getContactDisplayName(Author author, @Nullable String alias) { String name = author.getName(); From 9a6bb4b203871f751cb2fb26a93f49dfdea55f97 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 28 Jun 2023 14:54:25 -0300 Subject: [PATCH 10/14] Set dozed to true when we are in LowPowerStandby --- .../briar/android/DozeWatchdogImpl.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/DozeWatchdogImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/DozeWatchdogImpl.java index b22214700..16aebd676 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/DozeWatchdogImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/DozeWatchdogImpl.java @@ -10,14 +10,20 @@ import org.briarproject.bramble.api.lifecycle.Service; import org.briarproject.briar.api.android.DozeWatchdog; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Logger; import static android.content.Context.POWER_SERVICE; import static android.os.Build.VERSION.SDK_INT; import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED; import static android.os.PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED; +import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; class DozeWatchdogImpl implements DozeWatchdog, Service { + private static final Logger LOG = + getLogger(DozeWatchdogImpl.class.getName()); + private final Context appContext; private final AtomicBoolean dozed = new AtomicBoolean(false); private final BroadcastReceiver receiver = new DozeBroadcastReceiver(); @@ -57,11 +63,14 @@ class DozeWatchdogImpl implements DozeWatchdog, Service { (PowerManager) appContext.getSystemService(POWER_SERVICE); if (ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) { if (pm.isDeviceIdleMode()) dozed.set(true); - } else if (ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED.equals( - action)) { - // pm.isLowPowerStandbyEnabled(); - // TODO what do we do with this now? Disable Tor? - // broadcast network disabled events? + } else if (SDK_INT >= 33 && + ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED.equals(action)) { + if (pm.isLowPowerStandbyEnabled()) { + if (LOG.isLoggable(WARNING)) { + LOG.warning("System is in low power standby mode"); + } + dozed.set(true); + } } } } From c77eaf16d90ed0b16e9e4175b598a4ab1d03b759 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 28 Jun 2023 15:01:58 -0300 Subject: [PATCH 11/14] Log more mode changes in AndroidBatteryManager --- .../battery/AndroidBatteryManager.java | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/battery/AndroidBatteryManager.java b/bramble-android/src/main/java/org/briarproject/bramble/battery/AndroidBatteryManager.java index 7b675a821..df659e625 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/battery/AndroidBatteryManager.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/battery/AndroidBatteryManager.java @@ -17,13 +17,17 @@ import java.util.logging.Logger; import javax.inject.Inject; +import androidx.annotation.RequiresApi; + import static android.content.Intent.ACTION_BATTERY_CHANGED; import static android.content.Intent.ACTION_POWER_CONNECTED; import static android.content.Intent.ACTION_POWER_DISCONNECTED; import static android.os.BatteryManager.EXTRA_PLUGGED; import static android.os.Build.VERSION.SDK_INT; +import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED; import static android.os.PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED; import static android.os.PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED; +import static android.os.PowerManager.ACTION_POWER_SAVE_MODE_CHANGED; import static java.util.logging.Level.INFO; import static java.util.logging.Logger.getLogger; @@ -61,6 +65,8 @@ class AndroidBatteryManager implements BatteryManager, Service { IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_POWER_CONNECTED); filter.addAction(ACTION_POWER_DISCONNECTED); + filter.addAction(ACTION_POWER_SAVE_MODE_CHANGED); + if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED); if (SDK_INT >= 33) { filter.addAction(ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED); filter.addAction(ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED); @@ -84,7 +90,17 @@ class AndroidBatteryManager implements BatteryManager, Service { eventBus.broadcast(new BatteryEvent(true)); else if (ACTION_POWER_DISCONNECTED.equals(action)) eventBus.broadcast(new BatteryEvent(false)); - else if (SDK_INT >= 33 && LOG.isLoggable(INFO) && + else if (SDK_INT >= 23 && + ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action) && + LOG.isLoggable(INFO)) { + LOG.info("Device idle mode changed to: " + + getPowerManager(ctx).isDeviceIdleMode()); + } else if (SDK_INT >= 23 && + ACTION_POWER_SAVE_MODE_CHANGED.equals(action) && + LOG.isLoggable(INFO)) { + LOG.info("Power save mode changed to: " + + getPowerManager(ctx).isPowerSaveMode()); + } else if (SDK_INT >= 33 && LOG.isLoggable(INFO) && ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED.equals(action)) { PowerManager powerManager = ctx.getSystemService(PowerManager.class); @@ -92,11 +108,15 @@ class AndroidBatteryManager implements BatteryManager, Service { powerManager.isLowPowerStandbyEnabled()); } else if (SDK_INT >= 33 && LOG.isLoggable(INFO) && ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED.equals(action)) { - PowerManager powerManager = - ctx.getSystemService(PowerManager.class); + PowerManager powerManager = getPowerManager(ctx); LOG.info("Light idle mode now is: " + powerManager.isDeviceLightIdleMode()); } } } + + @RequiresApi(api = 23) + private PowerManager getPowerManager(Context ctx) { + return ctx.getSystemService(PowerManager.class); + } } From 23df2a41c24c522d563e6c4f0b09294481e99643 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 28 Jun 2023 15:07:18 -0300 Subject: [PATCH 12/14] Add @NotNullByDefault annotation to ConditionManagers --- .../briarproject/briar/android/hotspot/ConditionManager.java | 2 ++ .../briarproject/briar/android/hotspot/ConditionManager29.java | 2 ++ .../briarproject/briar/android/hotspot/ConditionManager33.java | 2 ++ 3 files changed, 6 insertions(+) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager.java index 251310c50..3364251c6 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager.java @@ -3,6 +3,7 @@ package org.briarproject.briar.android.hotspot; import android.provider.Settings; import org.briarproject.briar.R; +import org.briarproject.nullsafety.NotNullByDefault; import java.util.logging.Logger; @@ -18,6 +19,7 @@ import static java.util.logging.Logger.getLogger; * As soon as {@link #checkAndRequestConditions()} returns true, * all conditions are fulfilled. */ +@NotNullByDefault class ConditionManager extends AbstractConditionManager { private static final Logger LOG = diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java index 381d0a694..547a44e92 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager29.java @@ -5,6 +5,7 @@ import android.provider.Settings; import org.briarproject.briar.R; import org.briarproject.briar.android.util.Permission; import org.briarproject.briar.android.util.PermissionUtils; +import org.briarproject.nullsafety.NotNullByDefault; import java.util.logging.Logger; @@ -32,6 +33,7 @@ import static org.briarproject.briar.android.util.PermissionUtils.showLocationDi * all conditions are fulfilled. */ @RequiresApi(29) +@NotNullByDefault class ConditionManager29 extends AbstractConditionManager { private static final Logger LOG = diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java index f33427338..89cf62e2b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/ConditionManager33.java @@ -5,6 +5,7 @@ import android.provider.Settings; import org.briarproject.briar.R; import org.briarproject.briar.android.util.Permission; import org.briarproject.briar.android.util.PermissionUtils; +import org.briarproject.nullsafety.NotNullByDefault; import java.util.logging.Logger; @@ -29,6 +30,7 @@ import static java.util.logging.Logger.getLogger; * all conditions are fulfilled. */ @RequiresApi(33) +@NotNullByDefault class ConditionManager33 extends AbstractConditionManager { private static final Logger LOG = From 74f8e84a9b361c136795edee059cef49cb9d1447 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 29 Jun 2023 10:57:49 -0300 Subject: [PATCH 13/14] React to device light idle mode in DozeWatchdog as well --- .../briar/android/DozeWatchdogImpl.java | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/DozeWatchdogImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/DozeWatchdogImpl.java index 16aebd676..01e406d82 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/DozeWatchdogImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/DozeWatchdogImpl.java @@ -12,9 +12,12 @@ import org.briarproject.briar.api.android.DozeWatchdog; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Logger; +import androidx.annotation.RequiresApi; + import static android.content.Context.POWER_SERVICE; import static android.os.Build.VERSION.SDK_INT; import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED; +import static android.os.PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED; import static android.os.PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; @@ -42,6 +45,7 @@ class DozeWatchdogImpl implements DozeWatchdog, Service { if (SDK_INT < 23) return; IntentFilter filter = new IntentFilter(ACTION_DEVICE_IDLE_MODE_CHANGED); if (SDK_INT >= 33) { + filter.addAction(ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED); filter.addAction(ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED); } appContext.registerReceiver(receiver, filter); @@ -63,14 +67,27 @@ class DozeWatchdogImpl implements DozeWatchdog, Service { (PowerManager) appContext.getSystemService(POWER_SERVICE); if (ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) { if (pm.isDeviceIdleMode()) dozed.set(true); - } else if (SDK_INT >= 33 && - ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED.equals(action)) { + } else if (SDK_INT >= 33) { + onReceive33(action, pm); + } + } + + @RequiresApi(33) + private void onReceive33(String action, PowerManager pm) { + if (ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED.equals(action)) { if (pm.isLowPowerStandbyEnabled()) { if (LOG.isLoggable(WARNING)) { LOG.warning("System is in low power standby mode"); } dozed.set(true); } + } else if (ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED.equals(action)) { + if (pm.isDeviceLightIdleMode()) { + if (LOG.isLoggable(WARNING)) { + LOG.warning("System is in light idle mode"); + } + dozed.set(true); + } } } } From 882f536b8deef1a16f82c4abcfa0d4d63414ae2c Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 30 Jun 2023 18:14:12 +0100 Subject: [PATCH 14/14] Don't try to get Bluetooth address from settings. --- .../org/briarproject/bramble/util/AndroidUtils.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java b/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java index 8705f6673..e18e4c6ea 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java @@ -63,10 +63,12 @@ public class AndroidUtils { return new Pair<>(address, "adapter"); } // Return the address from settings if it's valid and not fake - address = Settings.Secure.getString(ctx.getContentResolver(), - "bluetooth_address"); - if (isValidBluetoothAddress(address)) { - return new Pair<>(address, "settings"); + if (SDK_INT < 33) { + address = Settings.Secure.getString(ctx.getContentResolver(), + "bluetooth_address"); + if (isValidBluetoothAddress(address)) { + return new Pair<>(address, "settings"); + } } // Try to get the address via reflection address = getBluetoothAddressByReflection(adapter);