org.traccar.manager.MainFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.traccar.manager.MainFragment.java

Source

/*
 * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.traccar.manager;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;

import org.traccar.manager.model.Geofence;
import org.traccar.manager.ui.activity.TestUIActivity;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

import org.traccar.manager.model.Device;
import org.traccar.manager.model.Position;
import org.traccar.manager.model.Update;
import org.traccar.manager.model.User;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.ws.WebSocket;
import okhttp3.ws.WebSocketCall;
import okhttp3.ws.WebSocketListener;
import okio.Buffer;
import retrofit2.Retrofit;

public class MainFragment extends SupportMapFragment implements OnMapReadyCallback {

    public static final int REQUEST_DEVICE = 1;
    public static final int RESULT_SUCCESS = 1;

    private GoogleMap map;

    private Handler handler = new Handler();
    private ObjectMapper objectMapper = new ObjectMapper();

    private Map<Long, Device> devices = new HashMap<>();
    private Map<Long, Position> positions = new HashMap<>();
    private Map<Long, Marker> markers = new HashMap<>();

    private WebSocketCall webSocket;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
        getMapAsync(this);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.main, menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.action_devices:
            startActivityForResult(new Intent(getContext(), DevicesActivity.class), REQUEST_DEVICE);
            return true;
        case R.id.action_logout:
            PreferenceManager.getDefaultSharedPreferences(getContext()).edit()
                    .putBoolean(MainApplication.PREFERENCE_AUTHENTICATED, false).apply();
            ((MainApplication) getActivity().getApplication()).removeService();
            getActivity().finish();
            startActivity(new Intent(getContext(), LoginActivity.class));
            return true;
        case R.id.action_slidingbuttons:
            startActivity(new Intent(getContext(), TestUIActivity.class));
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_DEVICE && resultCode == RESULT_SUCCESS) {
            long deviceId = data.getLongExtra(DevicesFragment.EXTRA_DEVICE_ID, 0);
            String deviceStatus = data.getStringExtra(DevicesFragment.EXTRA_DEVICE_STATUS);

            Position position = positions.get(deviceId);
            if (position != null) {
                map.moveCamera(
                        CameraUpdateFactory.newLatLng(new LatLng(position.getLatitude(), position.getLongitude())));
                map.animateCamera(CameraUpdateFactory.zoomTo(15));
                Marker deviceStatusMarker = markers.get(deviceId);

                //markers.get(deviceId).showInfoWindow();
                // Set color based on device being online/offline

                switch (deviceStatus) {
                case "online":
                    deviceStatusMarker
                            .setIcon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
                    deviceStatusMarker.setTitle("Online");
                    break;
                case "offline": // Never coming here as code can't figure between nonreachable and offline
                    deviceStatusMarker
                            .setIcon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE));
                    deviceStatusMarker.setTitle("Offline");
                    break;
                default:
                    deviceStatusMarker
                            .setIcon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_YELLOW));
                    deviceStatusMarker.setTitle("Offline");
                    break;
                }

                //show the marker 
                deviceStatusMarker.showInfoWindow();
            }
        }
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        map = googleMap;

        map.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
            @Override
            public View getInfoWindow(Marker marker) {
                return null;
            }

            @Override
            public View getInfoContents(Marker marker) {
                View view = getLayoutInflater(null).inflate(R.layout.view_info, null);
                ((TextView) view.findViewById(R.id.title)).setText(marker.getTitle());
                ((TextView) view.findViewById(R.id.details)).setText(marker.getSnippet());
                return view;
            }
        });

        createWebSocket();
    }

    private String formatDetails(Position position) {
        FragmentActivity activity = getActivity();
        if (activity == null) {
            return "";
        }
        final MainApplication application = (MainApplication) activity.getApplication();
        final User user = application.getUser();

        SimpleDateFormat dateFormat = null;
        if (user.getTwelveHourFormat()) {
            dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a");
        } else {
            dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }

        String speedUnit = "";
        double factor = 1;
        if (user.getSpeedUnit().equals("kn")) {
            speedUnit = getString(R.string.user_kn);
            factor = 1;
        } else if (user.getSpeedUnit().equals("kmh")) {
            speedUnit = getString(R.string.user_kmh);
            factor = 1.852;
        } else if (user.getSpeedUnit().equals("mph")) {
            speedUnit = getString(R.string.user_mph);
            factor = 1.15078;
        }
        double speed = position.getSpeed() * factor;

        return new StringBuilder().append(getString(R.string.position_time)).append(": ")
                .append(dateFormat.format(position.getFixTime())).append('\n')
                .append(getString(R.string.position_latitude)).append(": ")
                .append(String.format("%.5f", position.getLatitude())).append('\n')
                .append(getString(R.string.position_longitude)).append(": ")
                .append(String.format("%.5f", position.getLongitude())).append('\n')
                .append(getString(R.string.position_altitude)).append(": ")
                .append(String.format("%.1f", position.getAltitude())).append('\n')
                .append(getString(R.string.position_speed)).append(": ").append(String.format("%.1f", speed))
                .append(' ').append(speedUnit).append('\n').append(getString(R.string.position_course)).append(": ")
                .append(String.format("%.1f", position.getCourse())).toString();
    }

    private void handleMessage(String message) throws IOException {
        Update update = objectMapper.readValue(message, Update.class);
        if (update != null && update.positions != null) {
            for (Position position : update.positions) {
                long deviceId = position.getDeviceId();
                LatLng location = new LatLng(position.getLatitude(), position.getLongitude());
                Marker marker = markers.get(deviceId);
                if (marker == null) {
                    marker = map.addMarker(
                            new MarkerOptions().title(devices.get(deviceId).getName()).position(location));
                    markers.put(deviceId, marker);
                } else {
                    marker.setPosition(location);

                }
                marker.setSnippet(formatDetails(position));
                positions.put(deviceId, position);
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (webSocket != null) {
            webSocket.cancel();
        }
    }

    private void reconnectWebSocket() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (getActivity() != null) {
                    createWebSocket();
                }
            }
        });
    }

    private void createWebSocket() {
        final MainApplication application = (MainApplication) getActivity().getApplication();
        application.getServiceAsync(new MainApplication.GetServiceCallback() {
            @Override
            public void onServiceReady(final OkHttpClient client, final Retrofit retrofit, WebService service) {
                User user = application.getUser();
                map.moveCamera(CameraUpdateFactory
                        .newLatLngZoom(new LatLng(user.getLatitude(), user.getLongitude()), user.getZoom()));
                service.getDevices().enqueue(new WebServiceCallback<List<Device>>(getContext()) {
                    @Override
                    public void onSuccess(retrofit2.Response<List<Device>> response) {
                        for (Device device : response.body()) {
                            devices.put(device.getId(), device);
                        }

                        Request request = new Request.Builder()
                                .url(retrofit.baseUrl().url().toString() + "api/socket").build();
                        webSocket = WebSocketCall.create(client, request);
                        webSocket.enqueue(new WebSocketListener() {
                            @Override
                            public void onOpen(WebSocket webSocket, Response response) {
                            }

                            @Override
                            public void onFailure(IOException e, Response response) {
                                reconnectWebSocket();
                            }

                            @Override
                            public void onMessage(ResponseBody message) throws IOException {
                                final String data = message.string();
                                handler.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        try {
                                            handleMessage(data);
                                        } catch (IOException e) {
                                            Log.w(MainFragment.class.getSimpleName(), e);
                                        }
                                    }
                                });
                            }

                            @Override
                            public void onPong(Buffer payload) {
                            }

                            @Override
                            public void onClose(int code, String reason) {
                                reconnectWebSocket();
                            }
                        });
                    }
                });
            }
        });
    }

}