[android] Trace Path (a.k.a. Recent Track) #8183

Merged
kavikhalique merged 2 commits from recent-track-recorder into master 2024-08-24 07:36:19 +00:00
kavikhalique commented 2024-05-15 11:33:35 +00:00 (Migrated from github.com)

[Android] Implements Recent Track Recording in android app of OM

[Android] Implements Recent Track Recording in android app of OM
Jean-BaptisteC (Migrated from github.com) reviewed 2024-05-15 11:33:35 +00:00
rtsisyk reviewed 2024-05-15 11:56:12 +00:00

Actually, INTERVAL_TRACK_RECORDING_BACKGROUND = 10000 for the "Recent Track" feature is not a bad idea. The Recent Track probably doesn't need to be very precise. The only purpose of the Recent Track feature is to visualize the last traveled path on the map by using a dotted line. Even the 10 seconds pull interval is most likely good enough for this task. Let me play with this PR.

Actually, INTERVAL_TRACK_RECORDING_BACKGROUND = 10000 for the "Recent Track" feature is not a bad idea. The Recent Track probably doesn't need to be very precise. The only purpose of the Recent Track feature is to visualize the last traveled path on the map by using a dotted line. Even the 10 seconds pull interval is most likely good enough for this task. Let me play with this PR.
rtsisyk reviewed 2024-05-15 11:56:55 +00:00

Please try to avoid reformatting. Yes, I know that the code is not properly formatted according to the latest Android Studio settings. Let's fix it separately.

Please try to avoid reformatting. Yes, I know that the code is not properly formatted according to the latest Android Studio settings. Let's fix it separately.
rtsisyk reviewed 2024-05-15 11:57:53 +00:00
rtsisyk left a comment
Owner

Let me play with this PR on my real devices.

Let me play with this PR on my real devices.
kavikhalique (Migrated from github.com) reviewed 2024-05-15 11:58:27 +00:00
kavikhalique (Migrated from github.com) commented 2024-05-15 11:58:27 +00:00

Ok sir will keep in mind. 👍

Ok sir will keep in mind. 👍
rtsisyk reviewed 2024-05-16 16:25:11 +00:00
@ -0,0 +53,4 @@
}
@RequiresPermission(value = ACCESS_FINE_LOCATION)
public static void startForegroundService(@NonNull Context context)

I haven't seen any notifications, neither after enabling "Record Track" in the settings, nor after restarting the app. Please check for POST_NOTIFICATION permission. It is probably better to do from MwmActivity. See a7127ccde8/android/app/src/main/java/app/organicmaps/MwmActivity.java (L1843-L1854).

UPDATE: It has started to work after enabling notification in system settings:

I haven't seen any notifications, neither after enabling "Record Track" in the settings, nor after restarting the app. Please check for POST_NOTIFICATION permission. It is probably better to do from MwmActivity. See https://github.com/organicmaps/organicmaps/blob/a7127ccde88f2c0fd9a32142247714a01c3fbbab/android/app/src/main/java/app/organicmaps/MwmActivity.java#L1843-L1854. UPDATE: It has started to work after enabling notification in system settings: <img src="https://github.com/organicmaps/organicmaps/assets/1799054/da6aa149-91cd-448d-b4f1-06f0ad92d74d" width="350px">
kavikhalique (Migrated from github.com) reviewed 2024-05-16 18:40:17 +00:00
@ -0,0 +53,4 @@
}
@RequiresPermission(value = ACCESS_FINE_LOCATION)
public static void startForegroundService(@NonNull Context context)
kavikhalique (Migrated from github.com) commented 2024-05-16 18:40:17 +00:00

I have transferred the calling of service from preference class to mwmActivity class.

Although without notification permission i don't think it will show any notification. I tried with navigation as well but no notification shows if notification is turned off in settings.

I have transferred the calling of service from preference class to mwmActivity class. Although without notification permission i don't think it will show any notification. I tried with navigation as well but no notification shows if notification is turned off in settings.
rtsisyk reviewed 2024-05-17 11:09:44 +00:00
@ -0,0 +53,4 @@
}
@RequiresPermission(value = ACCESS_FINE_LOCATION)
public static void startForegroundService(@NonNull Context context)

This bug still present. Moreover, I don't see a notification when I start the app with the enabled option. I suspect that the foreground service doesn't start either. Enabling/disabling option in the settings fixes the issue.

6de4a18c0b210c8eded23a8842011c341f0d9bec (HEAD -> recent-track-recorder)
Author: kavikhalique kavikhalique3@gmail.com
Date: Fri May 17 02:45:21 2024 +0530

This bug still present. Moreover, I don't see a notification when I start the app with the enabled option. I suspect that the foreground service doesn't start either. Enabling/disabling option in the settings fixes the issue. 6de4a18c0b210c8eded23a8842011c341f0d9bec (HEAD -> recent-track-recorder) Author: kavikhalique <kavikhalique3@gmail.com> Date: Fri May 17 02:45:21 2024 +0530
rtsisyk reviewed 2024-05-17 11:28:57 +00:00

I have been playing with this PR for two days, using different devices. 10000ms is definitely not enough. It produces ragged tracks even when walking, not to mention driving. The effective minimum on Android is 1000ms (any value less than 1000ms is effectively treated as 1000ms). 10000ms is too slow. We'll determine the optimal value within this range or create a setting. For now, please update INTERVAL_TRACK_RECORDING_BACKGROUND to 3000ms.

I have been playing with this PR for two days, using different devices. 10000ms is definitely not enough. It produces ragged tracks even when walking, not to mention driving. The effective minimum on Android is 1000ms (any value less than 1000ms is effectively treated as 1000ms). 10000ms is too slow. We'll determine the optimal value within this range or create a setting. For now, please update INTERVAL_TRACK_RECORDING_BACKGROUND to 3000ms.
biodranik (Migrated from github.com) reviewed 2024-05-17 11:35:12 +00:00
biodranik (Migrated from github.com) commented 2024-05-17 11:35:12 +00:00

I suggest not wasting time on it now and always use the best precision/interval (zero). It will provide a good understanding and base raw data/stats that we can rely on later if decide to improve something.

Note that any OSMer or driver/cycler expects the track to be recorded with the max possible precision.

I suggest not wasting time on it now and always use the best precision/interval (zero). It will provide a good understanding and base raw data/stats that we can rely on later if decide to improve something. Note that any OSMer or driver/cycler expects the track to be recorded with the max possible precision.
rtsisyk requested changes 2024-05-17 11:56:08 +00:00

TrackRecorder is an abstract class for native methods, isn't it? I expect that TrackRecorderService.startForegroundService() will do all the work with native part. The invariant here is straightforward: native recording is enabled when the service is active. No service means no recording.

TrackRecorder is an abstract class for native methods, isn't it? I expect that TrackRecorderService.startForegroundService() will do all the work with native part. The invariant here is straightforward: native recording is enabled when the service is active. No service means no recording.

It is too early to start it here. Please try to start TrackRecordingService in onRenderingInitializationFinished() after restoring navigation:

8d27c3250c/android/app/src/main/java/app/organicmaps/MwmActivity.java (L244-L257)

It is too early to start it here. Please try to start TrackRecordingService in onRenderingInitializationFinished() after restoring navigation: https://github.com/organicmaps/organicmaps/blob/8d27c3250c7e46be3fb0b01382de5d5739ebf99b/android/app/src/main/java/app/organicmaps/MwmActivity.java#L244-L257

I suggest removing these listeners and calling LocationHelper directly below. Keep things simple.

I suggest removing these listeners and calling LocationHelper directly below. Keep things simple.

TAG, not "kavi".

`TAG`, not `"kavi"`.

Please see resumeLocationInForeground() in this class.

Please see resumeLocationInForeground() in this class.

I suggest renaming resumeLocationInForeground() to onAppForeground() and extending it instead of adding one more wrapper.

I suggest renaming resumeLocationInForeground() to onAppForeground() and extending it instead of adding one more wrapper.

Update onCalcUpdateInterval() instead. It should take all use-cases into account, including navigation.

Update onCalcUpdateInterval() instead. It should take all use-cases into account, including navigation.

Please kindly check the existing logic of MwmApplication.onBackground().

8d27c3250c/android/app/src/main/java/app/organicmaps/MwmApplication.java (L354-L373)

I suggest reintegrating this part of the code into MwmApplication.onBackground() first to handle all use-cases. We will figure out which parts can be moved back to LocationHelper later.

Please kindly check the existing logic of MwmApplication.onBackground(). https://github.com/organicmaps/organicmaps/blob/8d27c3250c7e46be3fb0b01382de5d5739ebf99b/android/app/src/main/java/app/organicmaps/MwmApplication.java#L354-L373 I suggest reintegrating this part of the code into MwmApplication.onBackground() first to handle all use-cases. We will figure out which parts can be moved back to LocationHelper later.
@ -0,0 +4,4 @@
public class TrackRecorder
{
public static native void nativeSetEnabled(boolean enable);

I understand the part with native methods. However, I don't understand the purpose of this class at all. Why are all these listeners needed at all?

I understand the part with native methods. However, I don't understand the purpose of this class at all. Why are all these listeners needed at all?

No hard-coded strings please.

No hard-coded strings please.

No hard-coded strings please.

No hard-coded strings please.

TAG, not "kavi".

`TAG`, not `"kavi"`.
@ -0,0 +181,4 @@
locationHelper.addListener(this);
// Restart the location with more frequent refresh interval for Track Recording.
locationHelper.restartWithNewMode();

This conflicts with the navigation service. Please think about a situation when both services are working in parallel. In this case, the lower interval should be set.

This conflicts with the navigation service. Please think about a situation when both services are working in parallel. In this case, the lower interval should be set.

Please try to follow the existing pattern above and avoid hard-coded strings.

Please try to follow the existing pattern above and avoid hard-coded strings.

I suggest creating LocationHelper.onAppBackground()/onAppForeground() and call them from MwmActivity. AFAIK there are already some methonds like that. Let's keep things simple.

I suggest creating LocationHelper.onAppBackground()/onAppForeground() and call them from MwmActivity. AFAIK there are already some methonds like that. Let's keep things simple.
@ -69,4 +52,3 @@
<string-array name="mobile_data_options">
<item>@string/mobile_data_option_ask</item>
<item>@string/mobile_data_option_always</item>

What happened to these settings?

What happened to these settings?
kavikhalique (Migrated from github.com) reviewed 2024-05-17 11:58:59 +00:00
@ -69,4 +52,3 @@
<string-array name="mobile_data_options">
<item>@string/mobile_data_option_ask</item>
<item>@string/mobile_data_option_always</item>
kavikhalique (Migrated from github.com) commented 2024-05-17 11:58:59 +00:00

Since on and off was implemented separately so removed it from time selection section

Since on and off was implemented separately so removed it from time selection section
kavikhalique (Migrated from github.com) reviewed 2024-05-17 12:04:03 +00:00
@ -0,0 +181,4 @@
locationHelper.addListener(this);
// Restart the location with more frequent refresh interval for Track Recording.
locationHelper.restartWithNewMode();
kavikhalique (Migrated from github.com) commented 2024-05-17 12:04:03 +00:00

Yess i have to re-lookup into the whole implementation of interval and have to manage it systematically.

Yess i have to re-lookup into the whole implementation of interval and have to manage it systematically.
kavikhalique (Migrated from github.com) reviewed 2024-05-17 12:09:47 +00:00
@ -0,0 +4,4 @@
public class TrackRecorder
{
public static native void nativeSetEnabled(boolean enable);
kavikhalique (Migrated from github.com) commented 2024-05-17 12:09:47 +00:00

Actually after your suggestion to start the foreground service from mwmActivity, i created a listener class which notifies the listener in mwmActivity that track recording has started and then it starts the track recording service.

Actually after your suggestion to start the foreground service from mwmActivity, i created a listener class which notifies the listener in mwmActivity that track recording has started and then it starts the track recording service.
rtsisyk reviewed 2024-05-17 14:39:39 +00:00

I suggest not wasting time on it now and always use the best precision/interval (zero).

The sole purpose of the "Recent Track" feature is to display the most recent path traveled on the map, using dotted line. Is a 10-second interval sufficient for this purpose? It appears not. While the minimum value is 1 second, the optimal setting likely lies somewhere in between, perhaps around 3 seconds (TBD).

It will provide a good understanding and base raw data/stats that we can rely on later if decide to improve something.

Please elaborate. The app neither collector nor share any "stats".

Note that any OSMer or driver/cycler expects the track to be recorded with the max possible precision.

As I previously stated, the current feature in this PR provides the functionality to view the most recent path traveled on the map. The functionality of recording and sharing tracks with proper user controls will be addressed in the next phase. I probably agree with you that for the recording track for sharing or mapping, the best (=1 second precision) should be used.

> I suggest not wasting time on it now and always use the best precision/interval (zero). The sole purpose of the "Recent Track" feature is to display the most recent path traveled on the map, using dotted line. Is a 10-second interval sufficient for this purpose? It appears not. While the minimum value is 1 second, the optimal setting likely lies somewhere in between, perhaps around 3 seconds (TBD). > It will provide a good understanding and base raw data/stats that we can rely on later if decide to improve something. Please elaborate. The app neither collector nor share any "stats". > Note that any OSMer or driver/cycler expects the track to be recorded with the max possible precision. As I previously stated, the current feature in this PR provides the functionality to view the most recent path traveled on the map. The functionality of recording and sharing tracks with proper user controls will be addressed in the next phase. I probably agree with you that for the recording track for sharing or mapping, the best (=1 second precision) should be used.
rtsisyk reviewed 2024-05-17 14:40:27 +00:00
@ -0,0 +4,4 @@
public class TrackRecorder
{
public static native void nativeSetEnabled(boolean enable);

It should be inverted... MwmActivity is the central dispatch point.

It should be inverted... MwmActivity is the central dispatch point.
rtsisyk reviewed 2024-05-17 14:41:03 +00:00
@ -69,4 +52,3 @@
<string-array name="mobile_data_options">
<item>@string/mobile_data_option_ask</item>
<item>@string/mobile_data_option_always</item>

What was wrong with using 0 as OFF?

What was wrong with using 0 as OFF?
kavikhalique (Migrated from github.com) reviewed 2024-05-17 22:33:06 +00:00
@ -69,4 +52,3 @@
<string-array name="mobile_data_options">
<item>@string/mobile_data_option_ask</item>
<item>@string/mobile_data_option_always</item>
kavikhalique (Migrated from github.com) commented 2024-05-17 22:33:06 +00:00

There are two buttons one for turning off and turning on and another to set the duration.

If "off" will be there in hour selector too then it will be a duplicate functionality.

If we implement "off" button in hour selector too then i think there will not be any need of the on/off button because there will be only one click difference.

In ios, only one setting is there which have off button as well in the hour selector

The better solution would be to add the off button in hour selector and keep it there but move the on/off button somewhere which is more easy to access for user like the bottom sheet dialog box where we are planning to place track recorder button

There are two buttons one for turning off and turning on and another to set the duration. If "off" will be there in hour selector too then it will be a duplicate functionality. If we implement "off" button in hour selector too then i think there will not be any need of the on/off button because there will be only one click difference. In ios, only one setting is there which have off button as well in the hour selector The better solution would be to add the off button in hour selector and keep it there but move the on/off button somewhere which is more easy to access for user like the bottom sheet dialog box where we are planning to place track recorder button
rtsisyk reviewed 2024-05-24 11:17:11 +00:00
rtsisyk left a comment
Owner

Added a few comments. Sorry for being picky here, but since this is your first major contribution, please pay attention to the code style. I won't comment on it further.

Added a few comments. Sorry for being picky here, but since this is your first major contribution, please pay attention to the code style. I won't comment on it further.

What is about just calling onTrackRecordingStarted() ?

What is about just calling onTrackRecordingStarted() ?

why the order has changed? it could be important...

why the order has changed? it could be important...

please don't shuffle the code

please don't shuffle the code
  private static final long INTERVAL_TRACK_RECORDING_BACKGROUND = 0;
```suggestion private static final long INTERVAL_TRACK_RECORDING_BACKGROUND = 0; ```

it will pollute logs, please remove after finishing debugging

it will pollute logs, please remove after finishing debugging

it will pollute logs, please remove after finishing debugging

it will pollute logs, please remove after finishing debugging

We can do something like that:

    Logger.d(TAG, "provider = " + mLocationProvider.getClass().getSimpleName() + " location = " + location + " interval = " + mInterval);

But I think that you will see the actual interval between messages in the logs.

We can do something like that: ```suggestion Logger.d(TAG, "provider = " + mLocationProvider.getClass().getSimpleName() + " location = " + location + " interval = " + mInterval); ``` But I think that you will see the actual interval between messages in the logs.
@ -293,6 +294,9 @@ public class LocationHelper implements BaseLocationProvider.Listener
if (RoutingController.get().isNavigating())
return INTERVAL_NAVIGATION_MS;

!mAppInForeground doesn't matter here, just check of TrackRecorder.nativeIsEnabled()

!mAppInForeground doesn't matter here, just check of TrackRecorder.nativeIsEnabled()

let's not change interval depending on background/foreground. Just always use INTERVAL_TRACK_RECORDING_BACKGROUND if recording is enabled.

let's not change interval depending on background/foreground. Just always use INTERVAL_TRACK_RECORDING_BACKGROUND if recording is enabled.
@ -0,0 +4,4 @@
public class TrackRecorder
{
public static native void nativeSetEnabled(boolean enable);

I don't really buy this idea with listeners in this class. Can we just check the status of Recent Track in MwmActivity.onResume() and start or stop the service? It will be 2 lines of code instead of 100.

I don't really buy this idea with listeners in this class. Can we just check the status of Recent Track in MwmActivity.onResume() and start or stop the service? It will be 2 lines of code instead of 100.
@ -0,0 +181,4 @@
locationHelper.addListener(this);
// Restart the location with more frequent refresh interval for Track Recording.
locationHelper.restartWithNewMode();

Actually, it is no-op if the interval is the same. Even if we decide to use different intervals, Navigation will take precedence:

  private long calcLocationUpdatesInterval()
  {
    if (RoutingController.get().isNavigating())
      return INTERVAL_NAVIGATION_MS; <!-- takes precedence
    if (TrackRecorder.nativeIsEnabled())
      return INTERVAL_TRACK_RECORDING_BACKGROUND;
    ```
Actually, it is no-op if the interval is the same. Even if we decide to use different intervals, Navigation will take precedence: ``` private long calcLocationUpdatesInterval() { if (RoutingController.get().isNavigating()) return INTERVAL_NAVIGATION_MS; <!-- takes precedence if (TrackRecorder.nativeIsEnabled()) return INTERVAL_TRACK_RECORDING_BACKGROUND; ```

nit: fix identation

nit: fix identation
Can it be null? I don't see any checks in other parts: https://github.com/organicmaps/organicmaps/blob/36924897f83e2b453e219a8bd37754e9b7cec171/android/app/src/main/java/app/organicmaps/settings/SettingsPrefsFragment.java#L116-L118 https://github.com/organicmaps/organicmaps/blob/36924897f83e2b453e219a8bd37754e9b7cec171/android/app/src/main/java/app/organicmaps/settings/SettingsPrefsFragment.java#L116-L120

Why is String compared with Integer? Convert newValue to Integer first.

Why is String compared with Integer? Convert newValue to Integer first.

nit: move to the next line

nit: move to the next line

nit: please fix the code style here

nit: please fix the code style here

Why does string contain " ?

" hour"?

Why does string contain " ? `" hour"`?
kavikhalique (Migrated from github.com) reviewed 2024-05-24 11:27:31 +00:00
kavikhalique (Migrated from github.com) commented 2024-05-24 11:27:31 +00:00

Sorry this is a mistake i will remove it.
Actually it automatically got added to keep the space " " attached with that

Sorry this is a mistake i will remove it. Actually it automatically got added to keep the space " " attached with that
kavikhalique (Migrated from github.com) reviewed 2024-05-24 11:36:42 +00:00
kavikhalique (Migrated from github.com) commented 2024-05-24 11:36:42 +00:00

TrackRecorder is an abstract class for native methods, isn't it? I expect that TrackRecorderService.startForegroundService() will do all the work with native part. The invariant here is straightforward: native recording is enabled when the service is active. No service means no recording.

I searched on internet and I found that jni have nothing to do with class type.

> TrackRecorder is an abstract class for native methods, isn't it? I expect that TrackRecorderService.startForegroundService() will do all the work with native part. The invariant here is straightforward: native recording is enabled when the service is active. No service means no recording. I searched on internet and I found that jni have nothing to do with class type.
kavikhalique (Migrated from github.com) reviewed 2024-05-24 11:37:21 +00:00
kavikhalique (Migrated from github.com) reviewed 2024-05-24 11:43:23 +00:00
kavikhalique (Migrated from github.com) commented 2024-05-24 11:43:23 +00:00

ya intervals are already their in logs no need for introducing extra intervals. I will remove that log.

ya intervals are already their in logs no need for introducing extra intervals. I will remove that log.
kavikhalique (Migrated from github.com) reviewed 2024-05-24 11:56:53 +00:00
@ -0,0 +53,4 @@
}
@RequiresPermission(value = ACCESS_FINE_LOCATION)
public static void startForegroundService(@NonNull Context context)
kavikhalique (Migrated from github.com) commented 2024-05-24 11:56:53 +00:00

This problem is still their even after calling the requestPostNotification() method from MwmActivity, It do not asks permissions for notifications even if it disabled in setiings although functionality works fine but it do not shows any notification.
Please test this with navigation as well. @rtsisyk

This problem is still their even after calling the requestPostNotification() method from MwmActivity, It do not asks permissions for notifications even if it disabled in setiings although functionality works fine but it do not shows any notification. Please test this with navigation as well. @rtsisyk
kavikhalique (Migrated from github.com) reviewed 2024-05-24 12:05:14 +00:00
kavikhalique (Migrated from github.com) commented 2024-05-24 12:05:13 +00:00

please don't shuffle the code

actually i was doing some testing for non working of the service in background by adding extra permission of background location permission, in a hope to get it solved. So when i removed i might have missed the correct order. Sorry for that

> please don't shuffle the code actually i was doing some testing for non working of the service in background by adding extra permission of background location permission, in a hope to get it solved. So when i removed i might have missed the correct order. Sorry for that
kavikhalique (Migrated from github.com) reviewed 2024-05-24 12:13:05 +00:00
@ -0,0 +4,4 @@
public class TrackRecorder
{
public static native void nativeSetEnabled(boolean enable);
kavikhalique (Migrated from github.com) commented 2024-05-24 12:13:05 +00:00

I don't really buy this idea with listeners in this class. Can we just check the status of Recent Track in MwmActivity.onResume() and start or stop the service? It will be 2 lines of code instead of 100.

There is one UX issue-
Suppose a users enables the recent track recorder from settings and directly exits the app without going to map screen. In that case service will never be started.

If we will place this in onResume() method, service will only turn on when mwmActivity will be resumed (i.e user will return to map screen) and same for turning it off as well.

> I don't really buy this idea with listeners in this class. Can we just check the status of Recent Track in MwmActivity.onResume() and start or stop the service? It will be 2 lines of code instead of 100. There is one UX issue- Suppose a users enables the recent track recorder from settings and directly exits the app without going to map screen. In that case service will never be started. If we will place this in onResume() method, service will only turn on when mwmActivity will be resumed (i.e user will return to map screen) and same for turning it off as well.
rtsisyk reviewed 2024-05-25 14:37:04 +00:00

Kavi Khalique:

Testing data for Recent track recorder

Device name - Xiaomi Redmi 8a dual
Android - 10
MIUI 12 stable

1- interval 0 sec
Initial Percentage - 97
Duration - 1 hr
Percentage consumed - 3

2- interval 2 sec
Initial Percentage - 94
Duration - 1 hr 26 mins
Percentage consumed - 3

3- interval 10 sec
Initial Percentage - 91
Duration - 2 hour
Percentage consumed - 3

4- interval 3 sec
Initial Percentage - 88
Duration - 2 hour
Percentage consumed - 3

5- navigation enabled
Duration - 1 hour
Initial Percentage- 85
Percentage consumed - 3

6- interval - 3 sec
Duration - 2 hr
Initial Percentage - 82
Percentage consumed - 4

7- interval - 10 sec
Duration - 3 hr 23 min
Initial Percentage - 78
Percentage consumed - 4

Kavi Khalique: > Testing data for Recent track recorder > > Device name - Xiaomi Redmi 8a dual > Android - 10 > MIUI 12 stable > > 1- interval 0 sec > Initial Percentage - 97 > Duration - 1 hr > Percentage consumed - 3 > > 2- interval 2 sec > Initial Percentage - 94 > Duration - 1 hr 26 mins > Percentage consumed - 3 > > 3- interval 10 sec > Initial Percentage - 91 > Duration - 2 hour > Percentage consumed - 3 > > 4- interval 3 sec > Initial Percentage - 88 > Duration - 2 hour > Percentage consumed - 3 > > 5- navigation enabled > Duration - 1 hour > Initial Percentage- 85 > Percentage consumed - 3 > > 6- interval - 3 sec > Duration - 2 hr > Initial Percentage - 82 > Percentage consumed - 4 > > 7- interval - 10 sec > Duration - 3 hr 23 min > Initial Percentage - 78 > Percentage consumed - 4
rtsisyk reviewed 2024-05-25 14:37:58 +00:00

It looks like that 1 vs 2 vs 3 intervals don't really matter. 10 seconds is obviously not enough, but 1-2-3 seconds don't make any difference to the battery consumption. I am in favor of enforcing setting interval = 0 for all recordings. Let's settle on 0 and move forward. No more speculations on thi topics as part of this project.

It looks like that 1 vs 2 vs 3 intervals don't really matter. 10 seconds is obviously not enough, but 1-2-3 seconds don't make any difference to the battery consumption. I am in favor of enforcing setting interval = 0 for all recordings. Let's settle on 0 and move forward. No more speculations on thi topics as part of this project.
rtsisyk reviewed 2024-05-25 15:01:26 +00:00
rtsisyk left a comment
Owner

This small feature is functionally complete. Let's polish the code and merge it. The work on the full-featured track recorder will continue in new PRs.

This small feature is functionally complete. Let's polish the code and merge it. The work on the full-featured track recorder will continue in new PRs.

There are two cases:

  1. Starting/stopping the service after enabling/disabled it in the SettingsActivity.
    It is safe to call TrackRecordingService.startForegroundService(this)/stopService() from SettingsActivity.

  2. Starting the service with the app
    Keep this current code that check for the settings and call TrackRecordingService.startForegroundService(this) if enabled.

There are two cases: 1. Starting/stopping the service after enabling/disabled it in the SettingsActivity. It is safe to call TrackRecordingService.startForegroundService(this)/stopService() from SettingsActivity. 2. Starting the service with the app Keep this current code that check for the settings and call TrackRecordingService.startForegroundService(this) if enabled.

This instance will organically disappear after removing listeners.

This instance will organically disappear after removing listeners.

Please be careful here. It can lead into infinite loop. It would be better to not to add restartWithNewMode(); here.

Please be careful here. It can lead into infinite loop. It would be better to not to add restartWithNewMode(); here.
@ -0,0 +4,4 @@
public class TrackRecorder
{
public static native void nativeSetEnabled(boolean enable);

There is one UX issue-
Suppose a users enables the recent track recorder from settings and directly exits the app without going to map screen. In that case service will never be started.

Why don't just call TrackRecordingService.startForegroundService(this) from SettingsActivity? Why these listeners are needed?

> There is one UX issue- > Suppose a users enables the recent track recorder from settings and directly exits the app without going to map screen. In that case service will never be started. Why don't just call `TrackRecordingService.startForegroundService(this)` from SettingsActivity? Why these listeners are needed?
@ -0,0 +53,4 @@
}
@RequiresPermission(value = ACCESS_FINE_LOCATION)
public static void startForegroundService(@NonNull Context context)

This problem is still their even after calling the requestPostNotification() method from MwmActivity, It do not asks permissions for notifications even if it disabled in setiings although functionality works fine but it do not shows any notification. Please test this with navigation as well. @rtsisyk

POST_NOTIFICATIONS is available on Android 13+ (API 33+). Please see https://developer.android.com/develop/ui/views/notifications/notification-permission. Let's try to call requestPostNotificationsPermission() at least.

> This problem is still their even after calling the requestPostNotification() method from MwmActivity, It do not asks permissions for notifications even if it disabled in setiings although functionality works fine but it do not shows any notification. Please test this with navigation as well. @rtsisyk [POST_NOTIFICATIONS](https://developer.android.com/reference/android/Manifest.permission#POST_NOTIFICATIONS) is available on Android 13+ (API 33+). Please see https://developer.android.com/develop/ui/views/notifications/notification-permission. Let's try to call requestPostNotificationsPermission() at least.

Do we really need these settings in Config.java? I suppose that TrackRecorder.nativeSetEnabled() already saves the setting persistently via C++ code. Please kindly take a look at organicmaps/organicmaps#1807/files. The original patch didn't have Config.java changes at all.

Do we really need these settings in Config.java? I suppose that TrackRecorder.nativeSetEnabled() already saves the setting persistently via C++ code. Please kindly take a look at https://git.omaps.dev/organicmaps/organicmaps/pulls/1807/files#diff-4a1a76e5c1d535b59bc9159048bd2c941dc112f5052e4e8ec650756c1ed0eed0R594-R642. The original patch didn't have Config.java changes at all.

Could you please re-use existting strings from iOS? See organicmaps/organicmaps#1807/files

  1. Change tags = ios to tags = ios,android to in strings.txt
  2. Run ./tools/unix/generate_localizations.sh to regenerate values-*/strings.xml

Please refer to https://github.com/organicmaps/organicmaps/blob/master/docs/TRANSLATIONS.md for more details.

Could you please re-use existting strings from iOS? See https://git.omaps.dev/organicmaps/organicmaps/pulls/1807/files#diff-8e9891f34f779c3f69c75ce68b56207e638f199a26123422c079734a32496c7cR4138 1. Change `tags = ios` to `tags = ios,android` to in strings.txt 2. Run ./tools/unix/generate_localizations.sh to regenerate values-*/strings.xml Please refer to https://github.com/organicmaps/organicmaps/blob/master/docs/TRANSLATIONS.md for more details.
kavikhalique (Migrated from github.com) reviewed 2024-05-25 15:04:12 +00:00
kavikhalique (Migrated from github.com) commented 2024-05-25 15:04:12 +00:00

Yes i was about to ask you the same. I think it can be removed its redundant.
Will remove it 👍

Yes i was about to ask you the same. I think it can be removed its redundant. Will remove it 👍
kavikhalique (Migrated from github.com) reviewed 2024-05-29 21:11:51 +00:00
@ -0,0 +4,4 @@
public class TrackRecorder
{
public static native void nativeSetEnabled(boolean enable);
kavikhalique (Migrated from github.com) commented 2024-05-29 21:11:51 +00:00

Since settings has been removed so all these are also gone : )

Since settings has been removed so all these are also gone : )
rtsisyk reviewed 2024-05-30 12:53:02 +00:00
@ -0,0 +53,4 @@
}
@RequiresPermission(value = ACCESS_FINE_LOCATION)
public static void startForegroundService(@NonNull Context context)

Please call requestPostNotificationsPermission() as well as check for location!

Please call requestPostNotificationsPermission() as well as check for location!
rtsisyk reviewed 2024-07-30 09:35:04 +00:00
rtsisyk left a comment
Owner

This PR generally looks good. Let's merge organicmaps/organicmaps#8399 first and then rebase this one.

This PR generally looks good. Let's merge https://git.omaps.dev/organicmaps/organicmaps/pulls/8399 first and then rebase this one.

Don't we need to set OFF icon here also?

Don't we need to set OFF icon here also?
Please rework to use strings.txt. https://github.com/organicmaps/organicmaps/blob/master/docs/TRANSLATIONS.md#translation-files
biodranik (Migrated from github.com) reviewed 2024-08-06 21:10:07 +00:00
biodranik (Migrated from github.com) commented 2024-08-06 20:59:27 +00:00
  1. Why is it needed?
  2. If it's needed, should the implementation request permission properly?

From API level 23 and onward, you have to declare ACCESS_NOTIFICATION_POLICY permission in the manifest AND then the user needs to grant your app access to toggle Do Not Disturb. You can check if the access is granted with NotificationManager#isNotificationPolicyAccessGranted(). If your package do not have access, start an ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS intent so the user can give your app access.

https://stackoverflow.com/questions/43123650/android-request-access-notification-policy-and-mute-phone

1. Why is it needed? 2. If it's needed, should the implementation request permission properly? > From API level 23 and onward, you have to declare ACCESS_NOTIFICATION_POLICY permission in the manifest AND then the user needs to grant your app access to toggle Do Not Disturb. You can check if the access is granted with [NotificationManager#isNotificationPolicyAccessGranted()](https://developer.android.com/reference/android/app/NotificationManager.html#isNotificationPolicyAccessGranted()). If your package do not have access, start an ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS intent so the user can give your app access. https://stackoverflow.com/questions/43123650/android-request-access-notification-policy-and-mute-phone
@ -1918,10 +1930,16 @@ public class MwmActivity extends BaseMwmFragmentActivity
Logger.w(LOCATION_TAG, "Permission " + permission + " has been refused");
}
biodranik (Migrated from github.com) commented 2024-08-06 21:00:30 +00:00

space after if here and in other places.

space after if here and in other places.
biodranik (Migrated from github.com) commented 2024-08-06 21:00:59 +00:00

Let's call it startTrackRecording to avoid renaming later.

Let's call it startTrackRecording to avoid renaming later.
biodranik (Migrated from github.com) commented 2024-08-06 21:03:49 +00:00
  1. Let's rename TracePath to TrackRecorder everywhere for consistency and to avoid renaming later.
  2. The use of this variable is not clear, is there a better way/naming to make it clearer?
1. Let's rename TracePath to TrackRecorder everywhere for consistency and to avoid renaming later. 2. The use of this variable is not clear, is there a better way/naming to make it clearer?
biodranik (Migrated from github.com) commented 2024-08-06 21:06:07 +00:00

Don't use one-line ifs, they're harder to debug.

Don't use one-line ifs, they're harder to debug.
@ -0,0 +161,4 @@
startForeground(TrackRecordingService.TRACK_REC_NOTIFICATION_ID, getNotificationBuilder(this).build());
} catch (ForegroundServiceStartNotAllowedException e)
{
Logger.e(TAG, "Oops! ForegroundService is not allowed", e);
biodranik (Migrated from github.com) commented 2024-08-06 21:05:36 +00:00

Should user see some UI explanation of why it doesn't start?

Should user see some UI explanation of why it doesn't start?
biodranik (Migrated from github.com) commented 2024-08-06 21:06:51 +00:00
  1. Why 0?
  2. Can it be replaced by a number 5?
1. Why 0? 2. Can it be replaced by a number 5?
rtsisyk reviewed 2024-08-06 21:32:29 +00:00
@ -0,0 +161,4 @@
startForeground(TrackRecordingService.TRACK_REC_NOTIFICATION_ID, getNotificationBuilder(this).build());
} catch (ForegroundServiceStartNotAllowedException e)
{
Logger.e(TAG, "Oops! ForegroundService is not allowed", e);
This case never happens. https://github.com/organicmaps/organicmaps/blob/bafee9fa0b60654a512184e07c1afa785796abc9/android/app/src/main/java/app/organicmaps/routing/NavigationService.java#L227-L236
rtsisyk reviewed 2024-08-06 21:33:50 +00:00

All these flags are subject to replacement with enums to differentiate between navigation/recording actions when requesting permissions.

All these flags are subject to replacement with enums to differentiate between navigation/recording actions when requesting permissions.
rtsisyk reviewed 2024-08-07 07:38:56 +00:00
@ -207,3 +209,4 @@
private boolean mLocationPermissionRequestedForRecording = false;
@SuppressWarnings("NotNullFieldNotInitialized")
@NonNull

It is hard to explain, but this code differs from the branch I've pushed yesterday. Something is wrong with GitHub.

It is hard to explain, but this code differs from the branch I've pushed yesterday. Something is wrong with GitHub.
kavikhalique (Migrated from github.com) reviewed 2024-08-10 15:08:24 +00:00
kavikhalique (Migrated from github.com) commented 2024-08-10 15:08:23 +00:00

using this permission we can show notifications on lock screen as well
Its implementation was already there but since this permission was not there thats why notifications for navigations and trace path were not shown on lockscreen.

using this permission we can show notifications on lock screen as well Its implementation was already there but since this permission was not there thats why notifications for navigations and trace path were not shown on lockscreen.
kavikhalique (Migrated from github.com) reviewed 2024-08-10 15:10:31 +00:00
kavikhalique (Migrated from github.com) commented 2024-08-10 15:10:31 +00:00

this log got pushed by mistake : )

this log got pushed by mistake : )
kavikhalique (Migrated from github.com) reviewed 2024-08-10 15:25:07 +00:00
kavikhalique (Migrated from github.com) commented 2024-08-10 15:25:07 +00:00

The logic is it only shows on icon if feature is turned on in all other cases it shows off icon.
So we dont actually have to explicitly set it to off.

The logic is it only shows on icon if feature is turned on in all other cases it shows off icon. So we dont actually have to explicitly set it to off.
kavikhalique (Migrated from github.com) reviewed 2024-08-10 19:23:41 +00:00
kavikhalique (Migrated from github.com) commented 2024-08-10 19:23:41 +00:00

What is the preferred way then?

What is the preferred way then?
biodranik (Migrated from github.com) reviewed 2024-08-10 19:24:45 +00:00
biodranik (Migrated from github.com) commented 2024-08-10 19:24:45 +00:00
if (x)
  do = y;
``` if (x) do = y; ```
rtsisyk reviewed 2024-08-12 20:17:22 +00:00

What breaks if we remove this permission?

What breaks if we remove this permission?
rtsisyk approved these changes 2024-08-13 07:08:01 +00:00
biodranik (Migrated from github.com) reviewed 2024-08-13 15:22:01 +00:00
biodranik (Migrated from github.com) left a comment

Thanks, looks good in general. Shall we test it in alpha/beta first before the merge?

Thanks, looks good in general. Shall we test it in alpha/beta first before the merge?
biodranik (Migrated from github.com) commented 2024-08-13 15:10:42 +00:00

OSMand, for example, does not declare this permission. Is it really needed?

OSMand, for example, does not declare this permission. Is it really needed?
biodranik (Migrated from github.com) commented 2024-08-13 15:11:57 +00:00

Is a coarse permission check required? Or only a fine permission check can be done?

Is a coarse permission check required? Or only a fine permission check can be done?
biodranik (Migrated from github.com) commented 2024-08-13 15:13:19 +00:00

Is badge count -1 a valid value?

Is badge count -1 a valid value?
biodranik (Migrated from github.com) commented 2024-08-13 15:13:47 +00:00

nit

    Logger.i(TAG, "onAppForeground");
nit ```suggestion Logger.i(TAG, "onAppForeground"); ```
@ -0,0 +55,4 @@
@RequiresPermission(value = ACCESS_FINE_LOCATION)
public static void startForegroundService(@NonNull Context context)
{
if (TrackRecorder.nativeGetDuration() != 24)
biodranik (Migrated from github.com) commented 2024-08-13 15:14:38 +00:00

nit: introduce a named constant to better understand what 24 means.

nit: introduce a named constant to better understand what 24 means.
@ -196,2 +223,4 @@
}
@OptIn(markerClass = com.google.android.material.badge.ExperimentalBadgeUtils.class)
public void updateMenuBadge()
biodranik (Migrated from github.com) commented 2024-08-13 15:17:42 +00:00

What are the pros of using experimental code?

What are the pros of using experimental code?
@ -206,2 +235,3 @@
final int verticalOffset = dpToPx(8, context) + dpToPx(Integer.toString(count).length() * 5, context);
final int verticalOffset = dpToPx(8, context) + dpToPx(Integer.toString(0)
.length() * 5, context);
BadgeUtils.detachBadgeDrawable(mBadgeDrawable, menuButton);
biodranik (Migrated from github.com) commented 2024-08-13 15:17:05 +00:00

nit

    final int verticalOffset = dpToPx(8, context) + dpToPx(Integer.toString(0).length() * 5, context);
nit ```suggestion final int verticalOffset = dpToPx(8, context) + dpToPx(Integer.toString(0).length() * 5, context); ```
biodranik (Migrated from github.com) commented 2024-08-13 15:18:21 +00:00

nit here and below: space after if

nit here and below: space after if
biodranik (Migrated from github.com) commented 2024-08-13 15:20:46 +00:00

Recording the track to avoid renaming it later for phase 2?

`Recording the track` to avoid renaming it later for phase 2?
rtsisyk reviewed 2024-08-14 08:57:57 +00:00

Probably it would be better not to touch the code that don't need to be changed.

Probably it would be better not to touch the code that don't need to be changed.
rtsisyk reviewed 2024-08-14 08:58:14 +00:00
@ -196,2 +223,4 @@
}
@OptIn(markerClass = com.google.android.material.badge.ExperimentalBadgeUtils.class)
public void updateMenuBadge()

@kavikhalique , is this experimental stuff needed at all?

@kavikhalique , is this experimental stuff needed at all?
kavikhalique (Migrated from github.com) reviewed 2024-08-14 15:18:59 +00:00
kavikhalique (Migrated from github.com) commented 2024-08-14 15:18:59 +00:00

actually it sends the count to show in the badge infront of bottom sheet menu item. But for trace path we needed only a dot so i sent -1 as a flag to distinguish between feasible number.

actually it sends the count to show in the badge infront of bottom sheet menu item. But for trace path we needed only a dot so i sent -1 as a flag to distinguish between feasible number.
kavikhalique (Migrated from github.com) reviewed 2024-08-14 15:20:31 +00:00
kavikhalique (Migrated from github.com) commented 2024-08-14 15:20:31 +00:00

checking both would be convenient i guess. I have copied it from the implementation of navigation system since it is already implemented and tested.

checking both would be convenient i guess. I have copied it from the implementation of navigation system since it is already implemented and tested.
kavikhalique (Migrated from github.com) reviewed 2024-08-14 16:17:55 +00:00
kavikhalique (Migrated from github.com) commented 2024-08-14 16:17:55 +00:00

What breaks if we remove this permission?

In my xiaomi device when i use this permission it shows notifications of OM on lockscreen and without this permission it do not shows anything.

But i tested on realme and motorola devices and nothing actually happens with and without this permission. Notification do not appears on lock screen in any case.

I feel this permission can be removed.

> What breaks if we remove this permission? In my xiaomi device when i use this permission it shows notifications of OM on lockscreen and without this permission it do not shows anything. But i tested on realme and motorola devices and nothing actually happens with and without this permission. Notification do not appears on lock screen in any case. I feel this permission can be removed.
kavikhalique (Migrated from github.com) reviewed 2024-08-14 16:30:07 +00:00
@ -196,2 +223,4 @@
}
@OptIn(markerClass = com.google.android.material.badge.ExperimentalBadgeUtils.class)
public void updateMenuBadge()
kavikhalique (Migrated from github.com) commented 2024-08-14 16:30:07 +00:00

This method was pre implemented and these experimental badge features too. I have just created one more similar method with arguments.

I guess this is necessary here since we are dealing with badge which is experimental probably.

Please have a look into updateBadge() method in current master branch. This is already used there to show badges.

This method was pre implemented and these experimental badge features too. I have just created one more similar method with arguments. I guess this is necessary here since we are dealing with badge which is experimental probably. Please have a look into updateBadge() method in current master branch. This is already used there to show badges.
rtsisyk requested changes 2024-08-15 08:31:54 +00:00
rtsisyk left a comment
Owner

Pleaase fix a crash in updateMenuBadge().

Pleaase fix a crash in updateMenuBadge().
@ -206,2 +235,3 @@
final int verticalOffset = dpToPx(8, context) + dpToPx(Integer.toString(count).length() * 5, context);
final int verticalOffset = dpToPx(8, context) + dpToPx(Integer.toString(0)
.length() * 5, context);
BadgeUtils.detachBadgeDrawable(mBadgeDrawable, menuButton);

This function crashes on attempt to make a route:

Process: app.organicmaps.debug, PID: 5395
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.getDrawingRect(android.graphics.Rect)' on a null object reference
at com.google.android.material.badge.BadgeUtils.setBadgeDrawableBounds(BadgeUtils.java:254)
at com.google.android.material.badge.BadgeUtils.attachBadgeDrawable(BadgeUtils.java:91)
at com.google.android.material.badge.BadgeUtils.attachBadgeDrawable(BadgeUtils.java:78)
at app.organicmaps.maplayer.MapButtonsController.updateMenuBadge(MapButtonsController.java:218)
at app.organicmaps.maplayer.MapButtonsController.$r8$lambda$Y3oUvRix7qylpmituPx43QoaZcg(Unknown Source:0)
at app.organicmaps.maplayer.MapButtonsController$$ExternalSyntheticLambda5.onChanged(D8$$SyntheticClass:0)
at androidx.lifecycle.LiveData.considerNotify(LiveData.java:133)
at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:146)
at androidx.lifecycle.LiveData$ObserverWrapper.activeStateChanged(LiveData.java:483)
at androidx.lifecycle.LiveData$LifecycleBoundObserver.onStateChanged(LiveData.java:440)
at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.jvm.kt:320)
at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.jvm.kt:198)
at androidx.lifecycle.LiveData.observe(LiveData.java:205)
at app.organicmaps.maplayer.MapButtonsController.onStart(MapButtonsController.java:355)
at androidx.fragment.app.Fragment.performStart(Fragment.java:3192)
at androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:648)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:304)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2164)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2059)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:702)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8751)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
This function crashes on attempt to make a route: ``` Process: app.organicmaps.debug, PID: 5395 java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.getDrawingRect(android.graphics.Rect)' on a null object reference at com.google.android.material.badge.BadgeUtils.setBadgeDrawableBounds(BadgeUtils.java:254) at com.google.android.material.badge.BadgeUtils.attachBadgeDrawable(BadgeUtils.java:91) at com.google.android.material.badge.BadgeUtils.attachBadgeDrawable(BadgeUtils.java:78) at app.organicmaps.maplayer.MapButtonsController.updateMenuBadge(MapButtonsController.java:218) at app.organicmaps.maplayer.MapButtonsController.$r8$lambda$Y3oUvRix7qylpmituPx43QoaZcg(Unknown Source:0) at app.organicmaps.maplayer.MapButtonsController$$ExternalSyntheticLambda5.onChanged(D8$$SyntheticClass:0) at androidx.lifecycle.LiveData.considerNotify(LiveData.java:133) at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:146) at androidx.lifecycle.LiveData$ObserverWrapper.activeStateChanged(LiveData.java:483) at androidx.lifecycle.LiveData$LifecycleBoundObserver.onStateChanged(LiveData.java:440) at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.jvm.kt:320) at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.jvm.kt:198) at androidx.lifecycle.LiveData.observe(LiveData.java:205) at app.organicmaps.maplayer.MapButtonsController.onStart(MapButtonsController.java:355) at androidx.fragment.app.Fragment.performStart(Fragment.java:3192) at androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:648) at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:304) at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2164) at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2059) at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002) at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:702) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:226) at android.os.Looper.loop(Looper.java:313) at android.app.ActivityThread.main(ActivityThread.java:8751) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135) ```
This repo is archived. You cannot comment on pull requests.
No labels
Accessibility
Accessibility
Address
Address
Android
Android
Android Auto
Android Auto
Android Automotive (AAOS)
Android Automotive (AAOS)
API
API
AppGallery
AppGallery
AppStore
AppStore
Battery and Performance
Battery and Performance
Blocker
Blocker
Bookmarks and Tracks
Bookmarks and Tracks
Borders
Borders
Bug
Bug
Build
Build
CarPlay
CarPlay
Classificator
Classificator
Community
Community
Core
Core
CrashReports
CrashReports
Cycling
Cycling
Desktop
Desktop
DevEx
DevEx
DevOps
DevOps
dev_sandbox
dev_sandbox
Directions
Directions
Documentation
Documentation
Downloader
Downloader
Drape
Drape
Driving
Driving
Duplicate
Duplicate
Editor
Editor
Elevation
Elevation
Enhancement
Enhancement
Epic
Epic
External Map Datasets
External Map Datasets
F-Droid
F-Droid
Fonts
Fonts
Frequently User Reported
Frequently User Reported
Fund
Fund
Generator
Generator
Good first issue
Good first issue
Google Play
Google Play
GPS
GPS
GSoC
GSoC
iCloud
iCloud
Icons
Icons
iOS
iOS
Legal
Legal
Linux Desktop
Linux Desktop
Linux packaging
Linux packaging
Linux Phone
Linux Phone
Mac OS
Mac OS
Map Data
Map Data
Metro
Metro
Navigation
Navigation
Need Feedback
Need Feedback
Night Mode
Night Mode
NLnet 2024-06-281
NLnet 2024-06-281
No Feature Parity
No Feature Parity
Opening Hours
Opening Hours
Outdoors
Outdoors
POI Info
POI Info
Privacy
Privacy
Public Transport
Public Transport
Raw Idea
Raw Idea
Refactoring
Refactoring
Regional
Regional
Regression
Regression
Releases
Releases
RoboTest
RoboTest
Route Planning
Route Planning
Routing
Routing
Ruler
Ruler
Search
Search
Security
Security
Styles
Styles
Tests
Tests
Track Recording
Track Recording
Translations
Translations
TTS
TTS
UI
UI
UX
UX
Walk Navigation
Walk Navigation
Watches
Watches
Web
Web
Wikipedia
Wikipedia
Windows
Windows
Won't fix
Won't fix
World Map
World Map
No milestone
No project
No assignees
2 participants
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: organicmaps/organicmaps-tmp#8183
No description provided.