Compare commits

..

5 Commits

Author SHA1 Message Date
Dennis Guse 1d0c6cdd92 Release: v4.12.1 2024-04-05 20:06:37 +02:00
Dennis Guse 4bfd65bb6d Bugfix: handle missing permissions properly.
Affected only SDK >= 33.

Fixes #1781.
2024-04-01 17:41:25 +02:00
Dennis Guse 48baece0e5 Bugfix: POST_NOTIFICATION permission is optional.
Affected only SDK >= 33.

Fixes #1880.
2024-04-01 17:12:53 +02:00
dependabot[bot] 3ac1226cdd Bump androidx.mediarouter:mediarouter from 1.6.0 to 1.7.0
Bumps androidx.mediarouter:mediarouter from 1.6.0 to 1.7.0.

---
updated-dependencies:
- dependency-name: androidx.mediarouter:mediarouter
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-21 05:58:13 +01:00
dependabot[bot] b4540121bb Bump com.android.tools.build:gradle from 8.3.0 to 8.3.1
Bumps com.android.tools.build:gradle from 8.3.0 to 8.3.1.

---
updated-dependencies:
- dependency-name: com.android.tools.build:gradle
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-19 20:53:21 +01:00
9 changed files with 51 additions and 21 deletions
+4 -4
View File
@@ -6,7 +6,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.3.0'
classpath 'com.android.tools.build:gradle:8.3.1'
}
}
@@ -64,8 +64,8 @@ android {
defaultConfig {
applicationId "de.dennisguse.opentracks"
versionCode 5725
versionName "v4.12.0"
versionCode 5730
versionName "v4.12.1"
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
@@ -135,7 +135,7 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.core:core:1.12.0'
implementation 'androidx.core:core-splashscreen:1.0.1'
implementation 'androidx.mediarouter:mediarouter:1.6.0'
implementation 'androidx.mediarouter:mediarouter:1.7.0'
androidTestImplementation 'androidx.test:core:1.5.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
@@ -0,0 +1,6 @@
v4.12.1: OpenTracks
Bugfix:
- Android 14: report missing permissions (instead of forced chrash with stacktrace)
- POST_NOTIFICATION is optional
@@ -40,6 +40,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import com.google.android.material.button.MaterialButton;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
@@ -47,6 +48,7 @@ import java.util.Objects;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.databinding.TrackListBinding;
import de.dennisguse.opentracks.services.MissingPermissionException;
import de.dennisguse.opentracks.services.RecordingStatus;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
@@ -159,7 +161,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
if (gpsStatusValue.isGpsStarted()) {
recordingStatusConnection.stopService(this);
} else {
TrackRecordingServiceConnection.executeForeground(this, (service, connection) -> service.tryStartSensors());
startSensorsOrRecording((service, connection) -> service.tryStartSensors());
}
}
});
@@ -178,7 +180,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
// Not Recording -> Recording
Log.i(TAG, "Starting recording");
updateGpsMenuItem(false, true);
TrackRecordingServiceConnection.executeForeground(this, (service, connection) -> {
startSensorsOrRecording((service, connection) -> {
Track.Id trackId = service.startNewTrack();
Intent newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordingActivity.class);
@@ -192,7 +194,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
}
// Recording -> Stop
ActivityUtils.vibrate(this, 1000);
ActivityUtils.vibrate(this, Duration.ofSeconds(1));
updateGpsMenuItem(false, false);
recordingStatusConnection.stopRecording(TrackListActivity.this);
viewBinding.trackListFabAction.setImageResource(R.drawable.ic_baseline_record_24);
@@ -445,4 +447,12 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
setFloatButton();
adapter.updateRecordingStatus(recordingStatus);
}
private void startSensorsOrRecording(TrackRecordingServiceConnection.Callback callback) {
try {
TrackRecordingServiceConnection.executeForeground(this, callback);
} catch (MissingPermissionException e) {
Toast.makeText(this, R.string.permission_recording_failed, Toast.LENGTH_LONG).show();
}
}
}
@@ -24,6 +24,7 @@ import androidx.viewpager2.adapter.FragmentStateAdapter;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayoutMediator;
import java.time.Duration;
import java.util.List;
import de.dennisguse.opentracks.chart.ChartFragment;
@@ -136,7 +137,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
viewBinding.trackRecordingFabAction.setBackgroundTintList(ContextCompat.getColorStateList(this, R.color.opentracks));
viewBinding.trackRecordingFabAction.setBackgroundColor(ContextCompat.getColor(this, R.color.opentracks));
viewBinding.trackRecordingFabAction.setOnLongClickListener((view) -> {
ActivityUtils.vibrate(this, 1000);
ActivityUtils.vibrate(this, Duration.ofSeconds(1));
trackRecordingServiceConnection.stopRecording(TrackRecordingActivity.this);
Intent newIntent = IntentUtils.newIntent(TrackRecordingActivity.this, TrackStoppedActivity.class)
.putExtra(TrackStoppedActivity.EXTRA_TRACK_ID, trackId);
@@ -0,0 +1,12 @@
package de.dennisguse.opentracks.services;
import de.dennisguse.opentracks.util.PermissionRequester;
public class MissingPermissionException extends RuntimeException {
private final PermissionRequester permissionRequester;
public MissingPermissionException(PermissionRequester permissionRequester) {
this.permissionRequester = permissionRequester;
}
}
@@ -20,7 +20,6 @@ import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ServiceInfo;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager.WakeLock;
@@ -46,7 +45,6 @@ import de.dennisguse.opentracks.services.announcement.VoiceAnnouncementManager;
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.util.PermissionRequester;
import de.dennisguse.opentracks.util.SystemUtils;
public class TrackRecordingService extends Service implements TrackPointCreator.Callback, SharedPreferences.OnSharedPreferenceChangeListener, TrackRecordingManager.IdleObserver {
@@ -207,18 +205,11 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
private synchronized void startSensors() {
if (isSensorStarted()) {
Log.i(TAG, "sensors already started; skipping");
return;
}
Log.i(TAG, "startSensors");
wakeLock = SystemUtils.acquireWakeLock(this, wakeLock);
trackPointCreator.start(this, handler);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
if (!PermissionRequester.RECORDING.hasPermission(this)) {
throw new RuntimeException("Android14: Please grant permissions LOCATION and NEARBY DEVICES (manually)");
}
}
ServiceCompat.startForeground(this, TrackRecordingServiceNotificationManager.NOTIFICATION_ID, notificationManager.setGPSonlyStarted(this), ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION + ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE);
}
@@ -20,6 +20,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.RemoteException;
@@ -29,6 +30,7 @@ import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import de.dennisguse.opentracks.BuildConfig;
import de.dennisguse.opentracks.util.PermissionRequester;
/**
* Wrapper for the track recording service.
@@ -157,6 +159,12 @@ public class TrackRecordingServiceConnection {
}
public static void executeForeground(Context context, Callback callback) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
if (!PermissionRequester.RECORDING.hasPermission(context)) {
throw new MissingPermissionException(PermissionRequester.RECORDING);
}
}
Callback withUnbind = (service, connection) -> {
callback.onConnected(service, connection);
connection.unbind(context);
@@ -15,6 +15,8 @@ import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.SearchView;
import java.time.Duration;
public class ActivityUtils {
private static final String TAG = ActivityUtils.class.getSimpleName();
@@ -32,12 +34,12 @@ public class ActivityUtils {
return searchView;
}
public static void vibrate(@NonNull Context context, int milliseconds) {
public static void vibrate(@NonNull Context context, Duration duration) {
final Vibrator vibrator = (Vibrator) context.getSystemService(VIBRATOR_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator.vibrate(VibrationEffect.createOneShot(milliseconds, VibrationEffect.DEFAULT_AMPLITUDE));
vibrator.vibrate(VibrationEffect.createOneShot(duration.toMillis(), VibrationEffect.DEFAULT_AMPLITUDE));
} else {
vibrator.vibrate(milliseconds);
vibrator.vibrate(duration.toMillis());
}
}
@@ -95,7 +95,7 @@ public class PermissionRequester {
ArrayList<String> recording = new ArrayList<>(GPS_PERMISSION);
recording.addAll(BLUETOOTH_PERMISSIONS);
RECORDING_PERMISSIONS = Collections.unmodifiableList(recording);
RECORDING_PERMISSIONS = Collections.unmodifiableList(new ArrayList<>(recording));
recording.addAll(NOTIFICATION_PERMISSIONS);