uk.org.freeflight.wifefinder.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for uk.org.freeflight.wifefinder.MainActivity.java

Source

/*
Copyright 2016 Alan Sparrow
    
This file is part of Wifefinder.
    
Wifefind is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
*/

package uk.org.freeflight.wifefinder;

import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.location.Location;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.SimpleCursorAdapter;
import android.widget.Spinner;
import android.widget.TextView;

import java.text.SimpleDateFormat;

public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {

    final static int PERMISSION_REQUEST_LOCATION = 1;

    final static String AIRCRAFT_ID_PREF = "AIRCRAFT_ID";
    final static String LAT_PREF = "LAT_PREF";
    final static String LON_PREF = "LON_PREF";
    final static String LOC_UPDATE_PREF = "LOC_UPDATE_PREF";

    final static int LOCATION_TIMEOUT = 30000;
    final static double LOCATION_ACCURACY = 25.0;

    // Maximum allowable age, in seconds
    final static long MAX_AGE = 12 * 3600;

    WifeFinderDb db;
    SimpleCursorAdapter aircraftCursorAdapter;

    long id;

    WifeFinderLocationService locationService;
    CountDownTimer locationTimer;

    AircraftPosition aircraftPosition;

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

        // Get previously used aircraft id
        id = getPreferences(MODE_PRIVATE).getLong(AIRCRAFT_ID_PREF, -1);

        // Setup App Bar
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_main);
        setSupportActionBar(toolbar);
        toolbar.setTitle(R.string.app_title);

        db = new WifeFinderDb(this);
        aircraftCursorAdapter = null;

        // Own location
        locationService = new WifeFinderLocationService(this);

        locationService.setLatitude(getPreferences(MODE_PRIVATE).getFloat(LAT_PREF, 0));
        locationService.setLongitude(getPreferences(MODE_PRIVATE).getFloat(LON_PREF, 0));

        // Aircraft position
        aircraftPosition = new AircraftPosition();

        // Own location locationTimer
        locationTimer = new CountDownTimer(LOCATION_TIMEOUT, 1000) {
            public void onTick(long msRemaining) {
                if (locationService.hasAccuracy() && (locationService.getAccuracy() < LOCATION_ACCURACY)) {
                    stopLocationUpdate();
                }
            }

            public void onFinish() {
                stopLocationUpdate();

                if (!locationService.hasAccuracy()) {
                    new AlertDialog.Builder(MainActivity.this).setTitle(R.string.no_location_title)
                            .setMessage(R.string.no_location_msg).setIcon(android.R.drawable.ic_dialog_info)
                            .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int which) {
                                }
                            }).show();
                }
            }
        };
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Create cursor adaptor for the spinner control
        Cursor cursor = db.makeCursor();
        String[] from = { WifeFinderDb.DbContract.AircraftTable.COLUMN_NAME_AIRCRAFT_REG };
        int[] to = { android.R.id.text1 };
        aircraftCursorAdapter = new SimpleCursorAdapter(this, R.layout.spinner_item, cursor, from, to, 0);
        aircraftCursorAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        // Spinner setup
        getMenuInflater().inflate(R.menu.menu_main, menu);
        MenuItem item = menu.findItem(R.id.aircraft_spinner);
        Spinner spinner = (Spinner) MenuItemCompat.getActionView(item);
        spinner.setAdapter(aircraftCursorAdapter);
        setSpinnerItemById(spinner, id);
        spinner.setOnItemSelectedListener(this);

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.action_update:
            startPositionUpdate();
            return true;

        case R.id.action_aircraft_list:
            Intent intent = new Intent(this, AircraftListActivity.class);
            startActivity(intent);
            return true;

        case R.id.action_update_location:
            startLocationUpdate();
            return true;

        case R.id.action_show_map:
            showMap();
            return true;

        default:
            return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int pos, long _id) {
        id = _id;
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {
        id = -1;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
            @NonNull int[] grantResults) {
        switch (requestCode) {
        case PERMISSION_REQUEST_LOCATION: {
            if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                startLocationUpdate();

            } else {
                new AlertDialog.Builder(this).setTitle("ERROR")
                        .setMessage("Sorry, Wife Finder doesn't work without access to ownLocation")
                        .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                finish();
                            }
                        }).setIcon(android.R.drawable.ic_dialog_alert).show();
            }
        }
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (aircraftCursorAdapter != null) {
            Cursor newCursor = db.makeCursor();
            Cursor oldCursor = aircraftCursorAdapter.swapCursor(newCursor);
            oldCursor.close();
        }

        if (getPreferences(MODE_PRIVATE).getBoolean(LOC_UPDATE_PREF, false)) {
            startLocationUpdate();
        }
    }

    @Override
    protected void onPause() {
        getPreferences(MODE_PRIVATE).edit().putLong(AIRCRAFT_ID_PREF, id)
                .putBoolean(LOC_UPDATE_PREF, locationService.isRunning())
                .putFloat(LON_PREF, (float) locationService.getLongitude())
                .putFloat(LAT_PREF, (float) locationService.getLatitude()).apply();

        stopLocationUpdate();

        super.onPause();
    }

    void setSpinnerItemById(Spinner spinner, long _id) {
        int spinnerCount = spinner.getCount();
        for (int i = 0; i < spinnerCount; i++) {
            Cursor value = (Cursor) spinner.getItemAtPosition(i);
            long id = value.getLong(value.getColumnIndex("_id"));
            if (id == _id) {
                spinner.setSelection(i);
            }
        }
    }

    void startLocationUpdate() {
        if (locationService.isRunning())
            return;

        if (!locationService.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)) {
            ActivityCompat.requestPermissions(this,
                    new String[] { android.Manifest.permission.ACCESS_FINE_LOCATION }, PERMISSION_REQUEST_LOCATION);
        } else {
            locationService.start();
            locationTimer.start();
        }
    }

    void stopLocationUpdate() {
        locationTimer.cancel();
        locationService.stop();

        updateDisplay();
    }

    void startPositionUpdate() {
        ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();

        if (networkInfo != null && networkInfo.isConnected()) {
            setDisplay(getString(R.string.updating_text), "", "", "");

            String aircraft_id = db.getAircraftId(id);
            String id_type = db.getAircraftIdType(id);
            new PositionUpdateTask(this, MAX_AGE).execute(id_type.toLowerCase() + ":" + aircraft_id.toUpperCase());

        } else {
            new AlertDialog.Builder(this).setTitle("Network Error")
                    .setMessage("Sorry, network connection is unavailable")
                    .setIcon(android.R.drawable.ic_dialog_alert)
                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                        }
                    }).show();
        }
    }

    void setPosition(AircraftPosition pos) {
        aircraftPosition = pos;
        updateDisplay();
    }

    void updateDisplay() {
        if (aircraftPosition.isValid) {
            Location p = new Location("");
            p.setLongitude(aircraftPosition.longitude);
            p.setLatitude(aircraftPosition.latitude);

            // Range
            String range_str = String.format("%.1f km", locationService.distanceTo(p) / 1000);

            // Bearing
            double bearing = locationService.bearingTo(p);
            if (bearing < 0) {
                bearing += 360;
            }
            String bearing_str = String.format("%.0f", bearing);

            // Altitude
            String altitude_str = String.format("%d ft", (int) (aircraftPosition.altitude * 3.28));

            // Time
            SimpleDateFormat outDateFormat = new SimpleDateFormat("HH:mm:ss");
            String time_str = outDateFormat.format(aircraftPosition.time);

            setDisplay(range_str, bearing_str, altitude_str, time_str);
        } else {
            setDisplay(getString(R.string.not_found_text), "", "", "");
        }
    }

    void setDisplay(String range, String bearing, String altitude, String time) {
        TextView tv_range = (TextView) findViewById(R.id.textView_range);
        TextView tv_bearing = (TextView) findViewById(R.id.textView_bearing);
        TextView tv_altitude = (TextView) findViewById(R.id.textView_altitude);
        TextView tv_time = (TextView) findViewById(R.id.textView_time);

        tv_range.setText(range);
        tv_bearing.setText(bearing);
        tv_altitude.setText(altitude);
        tv_time.setText(time);
    }

    void showMap() {
        // Display labelled marker at aircraft position
        String uri_str = String.format("geo:%f,%f?z=8&q=%f,%f(%s)", aircraftPosition.latitude,
                aircraftPosition.longitude, aircraftPosition.latitude, aircraftPosition.longitude,
                Uri.encode(db.getAircraftReg((id))));
        Uri gmmIntentUri = Uri.parse(uri_str);

        Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
        if (mapIntent.resolveActivity(getPackageManager()) != null) {
            startActivity(mapIntent);
        }
    }
}