1

I'm having an app that the user records his trip.The thing is when he has the app opened the whole time it works fine and the polyline shows all the trip**(see example on first photo**) but when the app gets minimized(because most of the users want to hear music) or the user turn the screen off,the polyline connects the two points from when the user had it open to where the user opens the app again**(see example on second photo)**

Correct Polyline CorrectPoly Wrong Polyline WrongPoly

Here is my class that contains the map

public class Map extends AppCompatActivity implements LocationListener, OnMapReadyCallback, NavigationView.OnNavigationItemSelectedListener {


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.map);

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayShowTitleEnabled(false);
    toolbar.setTitle("");
    toolbar.setSubtitle("");

    //gpsStatus = (TextView) findViewById(R.id.gpsStatus);
    dis = (TextView) findViewById(R.id.distancePreview);

    newActL = (RelativeLayout) findViewById(R.id.newAct);
    startActL = (RelativeLayout) findViewById(R.id.Act);
    timer = (TextView) findViewById(R.id.timePreview);

    newActB = (ImageButton) findViewById(R.id.newActB);
    stopActB = (ImageButton) findViewById(R.id.stopActB);
    gearMap = (ImageButton) findViewById(R.id.gearmap);

    List<String> spinnerArray = new ArrayList<String>();
    spinnerArray.add("Arrival");
    spinnerArray.add("Departure");

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(
            this, android.R.layout.simple_spinner_item, spinnerArray);

    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    sItems = (Spinner) findViewById(R.id.ardep);
    sItems.setAdapter(adapter);

    List<String> spinnerArray2 = new ArrayList<String>();
    spinnerArray2.add("Running");
    spinnerArray2.add("Walking");
    spinnerArray2.add("Cycling");
    spinnerArray2.add("Roller skating");
    spinnerArray2.add("Skateboarding");
    spinnerArray2.add("Kickbiking");
    spinnerArray2.add("Teleporting");

    ArrayAdapter<String> adapter2 = new ArrayAdapter<String>(
            this, android.R.layout.simple_spinner_item, spinnerArray2);

    adapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    actCombo = (Spinner) findViewById(R.id.actCombo);
    actCombo.setAdapter(adapter2);
    Calendar rightNow = Calendar.getInstance();
    int currentHour = rightNow.get(Calendar.HOUR_OF_DAY);
    if (currentHour < 12) {
        actCombo.setSelection(GetInfo.arract - 1);
        sItems.setSelection(0);
    } else {
        actCombo.setSelection(GetInfo.depact - 1);
        sItems.setSelection(1);
    }

    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
            ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
            3000,
            1, this);

    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapview);
    mapFragment.getMapAsync(this);
    line = new PolylineOptions().width(3).color(Color.BLUE);

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
            this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.addDrawerListener(toggle);
    toggle.syncState();

    navigationView = (NavigationView) findViewById(R.id.nav_view);
    headerView = navigationView.getHeaderView(0);
    fullnameside = (TextView) headerView.findViewById(R.id.fullnameside);
    emailside = (TextView) headerView.findViewById(R.id.emailside);
    fullnameside.setText("" + GetInfo.fullname);
    emailside.setText("" + GetInfo.email);

    navigationView.setNavigationItemSelectedListener(this);
    navigationView.getMenu().getItem(1).setChecked(true);

}

private void getLocation() {
    //Toast.makeText(getBaseContext(), "e paides", Toast.LENGTH_SHORT).show();
    String locationProvider = LocationManager.NETWORK_PROVIDER;
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        // TODO: Consider calling
        //    ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
        //                                          int[] grantResults)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.
        return;
    }
    Location location = locationManager.getLastKnownLocation(locationProvider);
    try {
        line.add(new LatLng(location.getLatitude(), location.getLongitude()));
        GMap.addMarker(new MarkerOptions().position(new LatLng(location.getLatitude(), location.getLongitude())).title(""));
        GMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location.getLatitude(), location.getLongitude()), 16.0f));
        steps++;
        getloc = true;
    } catch (NullPointerException e) {
        //Toast.makeText(this.getBaseContext(), "gyhg" + e.toString(), Toast.LENGTH_LONG).show();
    }
}

public void StopTrip(View v) {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setMessage("Stop and upload your trip?")
            .setCancelable(true)
            .setNegativeButton("NO", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {

                }
            })
            .setPositiveButton("YES", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    float finalDistance = (float) (distance / 1000.0);
                    if (finalDistance < 2) {
                        Intent myIntent = new Intent(Map.this, Profile.class);
                        startActivity(myIntent);
                    }
                    TimeBuff += MillisecondTime;
                    handler.removeCallbacks(runnable);
                    // newActL.setVisibility(View.GONE);
                    // startActL.setVisibility(View.VISIBLE);
                    enabledActivity = false;
                    //database post
                    try {
                        Date currentTime = Calendar.getInstance().getTime();
                        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
                        String formattedDate = df.format(currentTime);

                        Date currentTime2 = Calendar.getInstance().getTime();
                        SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd%20HH:mm:ss");
                        dateActEnd = df2.format(currentTime2);

                        String act = actCombo.getSelectedItem().toString();
                        String act_id = "7";
                        switch (act) {
                            case "Running":
                                act_id = "1";
                                break;
                            case "Walking":
                                act_id = "2";
                                break;
                            case "Cycling":
                                act_id = "3";
                                break;
                            case "Roller skating":
                                act_id = "4";
                                break;
                            case "Skateboarding":
                                act_id = "5";
                                break;
                            case "Kickbiking":
                                act_id = "6";
                                break;
                            case "Teleporting":
                                act_id = "7";
                                break;
                        }

                        String direcor;
                        if (sItems.getSelectedItem().toString().equals("Arrival"))
                            direcor = "arrival";
                        else
                            direcor = "departure";

                        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
                        StrictMode.setThreadPolicy(policy);
                        // String.format("%.1f", finalDistance)
                        URL obj = new URL("https://gekon.technologypark.cz/api/v1/record/create?user=" + LoginInfo.UserID
                                + "&date=" + formattedDate + "&distance=" + String.format("%.1f", finalDistance) + "&direction=" + direcor
                                + "&activity=" + act_id + "&polyline=" + PolyUtil.encode(line.getPoints()) + "&start=" + dateActStart
                                + "&end=" + dateActEnd + "&source=mobileapp");

                        HttpsURLConnection conn = (HttpsURLConnection) obj.openConnection();
                        conn.setRequestMethod("POST");
                        conn.setRequestProperty("ApiSecret", LoginInfo.ApiSecret);
                        conn.connect();
                        BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
                        StringBuilder sb = new StringBuilder();
                        String output;
                        while ((output = br.readLine()) != null)
                            sb.append(output);

                        JSONObject jsonObj = new JSONObject(sb.toString());
                        JSONObject curRecord = new JSONObject(jsonObj.getString("data"));

                        Trips.datet.add(currentTime);
                        Trips.datestr.add(formattedDate);
                        Trips.act.add(act_id);
                        Trips.tripType.add(sItems.getSelectedItem().toString());
                        Trips.dist.add(String.format("%.1f", finalDistance));
                        Trips.trip_ids.add(curRecord.getString("trip_id"));
                        Trips.calc(++Trips.points);

                        TripsCalendarInfo.datet.add(currentTime);
                        TripsCalendarInfo.act.add(act_id);
                        TripsCalendarInfo.act_str.add(act);
                        TripsCalendarInfo.tripType.add(sItems.getSelectedItem().toString());
                        TripsCalendarInfo.dist.add(String.format("%.1f", finalDistance));
                        TripsCalendarInfo.datestr.add(formattedDate);
                        TripsCalendarInfo.trip_ids.add(curRecord.getString("trip_id"));
                        TripsCalendarInfo.trip_source.add("mobileapp");
                        TripsCalendarInfo.polyline.add(PolyUtil.encode(line.getPoints()));
                        TripsCalendarInfo.CanItrip();

                        float km_up = Float.parseFloat(TripsInfo.km.get(TripsInfo.userRank - 1)) + finalDistance;
                        int trip_up = Integer.parseInt(TripsInfo.trips.get(TripsInfo.userRank - 1)) + 1;
                        TripsInfo.trips.set(TripsInfo.userRank - 1, "" + trip_up);
                        TripsInfo.km.set(TripsInfo.userRank - 1, String.format("%.1f", km_up));
                        TripsInfo.rankSort();

                        getloc = false;

                        Intent myIntent = new Intent(Map.this, Profile.class);
                        startActivity(myIntent);

                    } catch (Exception e) {
                        Toast.makeText(getBaseContext(), "Error upload, please check your options at gear button", Toast.LENGTH_LONG).show();
                    }
                }
            });
    float finalDistance = (float) (distance / 1000.0);
    if (finalDistance < 2) {
        builder.setMessage("Your trip is below 2km and it will not be counted.\nAre you sure you want to stop?");
    }
    AlertDialog alert = builder.create();
    alert.show();

}


public void StartAct(View v) {
    timer.setVisibility(View.VISIBLE);
    dis.setVisibility(View.VISIBLE);
    newActB.setVisibility(View.GONE);
    stopActB.setVisibility(View.VISIBLE);
    //gearMap.setVisibility(View.GONE);
    navigationView.setVisibility(View.GONE);
    //headerView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
    toolbar.setNavigationIcon(null);          // to hide Navigation icon
    //toolbar.setDisplayHomeAsUpEnabled(false);
    handler = new Handler();

    Date currentTime = Calendar.getInstance().getTime();
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd%20HH:mm:ss");
    dateActStart = df.format(currentTime);
    StartTime = SystemClock.uptimeMillis();
    handler.postDelayed(runnable, 0);

    startService(new Intent(this, LocationService.class));
    //enabledActivity = true;
}

public void ChangeAct(View v) {
    if (newActL.getVisibility() == View.GONE) {
        newActL.setVisibility(View.VISIBLE);
        startActL.setVisibility(View.GONE);
    } else {
        newActL.setVisibility(View.GONE);
        startActL.setVisibility(View.VISIBLE);
    }
}

public Runnable runnable = new Runnable() {

    public void run() {

        MillisecondTime = SystemClock.uptimeMillis() - StartTime;

        UpdateTime = TimeBuff + MillisecondTime;

        Seconds = (int) (UpdateTime / 1000);

        Minutes = Seconds / 60;

        Hours = Minutes / 60;

        Seconds = Seconds % 60;

        Minutes = Minutes % 60;

        MilliSeconds = (int) (UpdateTime % 100);

        timer.setText("Time: " + String.format("%02d", Hours) + ":"
                + String.format("%02d", Minutes) + ":"
                + String.format("%02d", Seconds));

        handler.postDelayed(this, 950);
    }

};

@Override
public void onMapReady(GoogleMap map) {
    GMap = map;
    GMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(49.8117806, 15.6970293), 6.0f));
    getloc=false;
    if (!getloc)
    getLocation();
}
Alex
  • 1,816
  • 5
  • 23
  • 39

1 Answers1

1

Here is the likely explanation:

  1. The user minimizes your app.
  2. Shortly thereafter, the app is destroyed as part of normal Android app management actions, causing the GPS to turn off.
  3. The user moves to a new location, and brings the app back to the foreground.
  4. onCreate() gets called again (since the Activity is being re-constructed), which resets your PolylineOptions object.
  5. Before the GPS has a chance to get a good fix, getLocation() is called by onMapReady(). Since the device doesn't know where it is yet, getLastKnownLocation() returns the last known location, some miles away.
  6. At some point, onLocationChanged() (not shown in the posted code) starts getting called again, thus drawing a new line direct to the user's current location.

SOLUTION

Simplest way to fix this is to implement a foreground Service, which is a long-lived component of your app that will be able to continue getting GPS information regardless of the state of the Activity. In this case, you'd move your Polyline initialization logic to Service.onCreate(), and have that implement onLocationChanged() instead of the activity.

See this answer for some code samples.

greeble31
  • 4,894
  • 2
  • 16
  • 30
  • Thank you very much for your answer.I will take a look and i will see what i can do with that! – Alex Nov 05 '18 at 18:15
  • can you please tell me if foreground services running even if i lock the screen phone? – Alex Nov 06 '18 at 15:14
  • 1
    Yes, the `Service` will stay alive. That does not necessarily mean that the phone won't go to sleep. If you need to ensure your thread(s) keep running, you can use a `WakeLock`. – greeble31 Nov 06 '18 at 15:45
  • Thanks!One more thing.I saw that WakeLocks don't let the screen turned off.I just want when the screen is of the getlocation and polyline will continue to work.Is this possible? – Alex Nov 07 '18 at 08:39
  • 1
    @AlexKolydas You're welcome. Sounds like you want a `PARTIAL_WAKE_LOCK`, [here's](https://stackoverflow.com/a/37841598/6759241) an example. – greeble31 Nov 07 '18 at 13:17