org.jnegre.android.osmonthego.service.ExportService.java Source code

Java tutorial

Introduction

Here is the source code for org.jnegre.android.osmonthego.service.ExportService.java

Source

/*
 * Copyright 2014  Jrme Ngre
 *
 * 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.jnegre.android.osmonthego.service;

import android.app.IntentService;
import android.content.Intent;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.text.format.DateFormat;
import android.util.Log;
import android.widget.Toast;

import org.apache.http.protocol.HTTP;
import org.jnegre.android.osmonthego.R;
import org.jnegre.android.osmonthego.provider.SurveyProviderMetaData.AddressTableMetaData;
import org.jnegre.android.osmonthego.provider.SurveyProviderMetaData.FixmeTableMetaData;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

public class ExportService extends IntentService {
    private final static String TAG = "ExportService";

    private final static String ACTION_EXPORT_OSM = "org.jnegre.android.osmonthego.service.action.EXPORT_OSM";
    private final static String EXTRA_INCLUDE_ADDRESS = "org.jnegre.android.osmonthego.service.extra.INCLUDE_ADDRESS";
    private final static String EXTRA_INCLUDE_FIXME = "org.jnegre.android.osmonthego.service.extra.INCLUDE_FIXME";

    private final static double MARGIN = 0.001;

    private final Handler handler;

    public static void startOsmExport(Context context, boolean includeAddress, boolean includeFixme) {
        Intent intent = new Intent(context, ExportService.class);
        intent.setAction(ACTION_EXPORT_OSM);
        intent.putExtra(EXTRA_INCLUDE_ADDRESS, includeAddress);
        intent.putExtra(EXTRA_INCLUDE_FIXME, includeFixme);
        context.startService(intent);
    }

    public ExportService() {
        super("ExportService");
        this.handler = new Handler();
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_EXPORT_OSM.equals(action)) {
                boolean includeAddress = intent.getBooleanExtra(EXTRA_INCLUDE_ADDRESS, false);
                boolean includeFixme = intent.getBooleanExtra(EXTRA_INCLUDE_FIXME, false);
                handleOsmExport(includeAddress, includeFixme);
            }
        }
    }

    /**
     * Handle export in the provided background thread
     */
    private void handleOsmExport(boolean includeAddress, boolean includeFixme) {
        //TODO handle empty survey
        //TODO handle bounds around +/-180

        if (!isExternalStorageWritable()) {
            notifyUserOfError();
            return;
        }

        int id = 0;
        double minLat = 200;
        double minLng = 200;
        double maxLat = -200;
        double maxLng = -200;
        StringBuilder builder = new StringBuilder();

        if (includeAddress) {
            Uri uri = AddressTableMetaData.CONTENT_URI;
            Cursor cursor = getContentResolver().query(uri, new String[] { //projection
                    AddressTableMetaData.LATITUDE, AddressTableMetaData.LONGITUDE, AddressTableMetaData.NUMBER,
                    AddressTableMetaData.STREET }, null, //selection string
                    null, //selection args array of strings
                    null); //sort order

            if (cursor == null) {
                notifyUserOfError();
                return;
            }

            try {
                int iLat = cursor.getColumnIndex(AddressTableMetaData.LATITUDE);
                int iLong = cursor.getColumnIndex(AddressTableMetaData.LONGITUDE);
                int iNumber = cursor.getColumnIndex(AddressTableMetaData.NUMBER);
                int iStreet = cursor.getColumnIndex(AddressTableMetaData.STREET);

                for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
                    //Gather values
                    double lat = cursor.getDouble(iLat);
                    double lng = cursor.getDouble(iLong);
                    String number = cursor.getString(iNumber);
                    String street = cursor.getString(iStreet);

                    minLat = Math.min(minLat, lat);
                    maxLat = Math.max(maxLat, lat);
                    minLng = Math.min(minLng, lng);
                    maxLng = Math.max(maxLng, lng);
                    builder.append("<node id=\"-").append(++id).append("\" lat=\"").append(lat).append("\" lon=\"")
                            .append(lng).append("\" version=\"1\" action=\"modify\">\n");
                    addOsmTag(builder, "addr:housenumber", number);
                    addOsmTag(builder, "addr:street", street);
                    builder.append("</node>\n");
                }
            } finally {
                cursor.close();
            }
        }

        if (includeFixme) {
            Uri uri = FixmeTableMetaData.CONTENT_URI;
            Cursor cursor = getContentResolver().query(uri, new String[] { //projection
                    FixmeTableMetaData.LATITUDE, FixmeTableMetaData.LONGITUDE, FixmeTableMetaData.COMMENT }, null, //selection string
                    null, //selection args array of strings
                    null); //sort order

            if (cursor == null) {
                notifyUserOfError();
                return;
            }

            try {
                int iLat = cursor.getColumnIndex(FixmeTableMetaData.LATITUDE);
                int iLong = cursor.getColumnIndex(FixmeTableMetaData.LONGITUDE);
                int iComment = cursor.getColumnIndex(FixmeTableMetaData.COMMENT);

                for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
                    //Gather values
                    double lat = cursor.getDouble(iLat);
                    double lng = cursor.getDouble(iLong);
                    String comment = cursor.getString(iComment);

                    minLat = Math.min(minLat, lat);
                    maxLat = Math.max(maxLat, lat);
                    minLng = Math.min(minLng, lng);
                    maxLng = Math.max(maxLng, lng);
                    builder.append("<node id=\"-").append(++id).append("\" lat=\"").append(lat).append("\" lon=\"")
                            .append(lng).append("\" version=\"1\" action=\"modify\">\n");
                    addOsmTag(builder, "fixme", comment);
                    builder.append("</node>\n");
                }
            } finally {
                cursor.close();
            }
        }

        try {
            File destinationFile = getDestinationFile();
            destinationFile.getParentFile().mkdirs();
            PrintWriter writer = new PrintWriter(destinationFile, "UTF-8");

            writer.println("<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>");
            writer.println("<osm version=\"0.6\" generator=\"OsmOnTheGo\">");
            writer.print("<bounds minlat=\"");
            writer.print(minLat - MARGIN);
            writer.print("\" minlon=\"");
            writer.print(minLng - MARGIN);
            writer.print("\" maxlat=\"");
            writer.print(maxLat + MARGIN);
            writer.print("\" maxlon=\"");
            writer.print(maxLng + MARGIN);
            writer.println("\" />");

            writer.println(builder);

            writer.print("</osm>");
            writer.close();

            if (writer.checkError()) {
                notifyUserOfError();
            } else {
                //FIXME i18n the subject and content
                Intent emailIntent = new Intent(Intent.ACTION_SEND);
                emailIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                emailIntent.setType(HTTP.OCTET_STREAM_TYPE);
                //emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"johndoe@exemple.com"});
                emailIntent.putExtra(Intent.EXTRA_SUBJECT, "OSM On The Go");
                emailIntent.putExtra(Intent.EXTRA_TEXT, "Your last survey.");
                emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(destinationFile));
                startActivity(emailIntent);
            }
        } catch (IOException e) {
            Log.e(TAG, "Could not write to file", e);
            notifyUserOfError();
        }

    }

    private void notifyUserOfError() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), R.string.msg_export_failed, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private static void addOsmTag(StringBuilder builder, String k, String v) {
        if (v != null) {
            builder.append("<tag k=\"").append(k).append("\" v=\"").append(v).append("\" />\n");
        }
    }

    private File getDestinationFile() {
        File externalStorage = Environment.getExternalStorageDirectory();
        String dirName = getApplicationInfo().packageName;
        File dir = new File(externalStorage, dirName);
        String fileName = DateFormat.format("'onthego-'yyyy-MM-dd_H-m'.osm'", new Date()).toString();
        return new File(dir, fileName);
    }

    /* Checks if external storage is available for read and write */
    private static boolean isExternalStorageWritable() {
        String state = Environment.getExternalStorageState();
        return Environment.MEDIA_MOUNTED.equals(state);
    }

}