cz.muni.fi.japanesedictionary.parser.ParserService.java Source code

Java tutorial

Introduction

Here is the source code for cz.muni.fi.japanesedictionary.parser.ParserService.java

Source

/**
 *     JapaneseDictionary - an JMDict browser for Android
 Copyright (C) 2013 Jaroslav Klech
     
 This program 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.
     
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
    
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package cz.muni.fi.japanesedictionary.parser;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;

import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.StatFs;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import cz.muni.fi.japanesedictionary.Const;
import cz.muni.fi.japanesedictionary.R;
import cz.muni.fi.japanesedictionary.main.MainActivity;
import cz.muni.fi.japanesedictionary.util.CompressFolder;

/**
 * Service for downloading and parsing dictionaries.
 * 
 * @author Bc. Jaroslav Klech
 * 
 */
public class ParserService extends Service {

    private static final String LOG_TAG = "ParserService";

    public static final String DICTIONARY_PATH = "http://android-japdict.rhcloud.com/cron/jmdict";
    public static final String KANJIDICT_PATH = "http://android-japdict.rhcloud.com/cron/kanjidic2";
    public static final String TATOEBA_INDICES_PATH = "http://android-japdict.rhcloud.com/cron/tatoebaindices";
    public static final String TATOEBA_SENTENCES_PATH = "http://android-japdict.rhcloud.com/cron/tatoebasentences";
    public static final String KANJIVG_PATH = "https://github.com/KanjiVG/kanjivg/releases/download/r20140816/kanjivg-20140816-main.zip";

    public static final String DICTIONARY_PREFERENCES = "cz.muni.fi.japanesedictionary";

    public static final Long downloadExpireTime = 60 * 60 * 3l;

    private URL mDownloadJMDictFrom = null;
    private File mDownloadJMDictTo = null;
    private boolean mDownloadingJMDict = false;

    private URL mDownloadKanjidicFrom = null;
    private File mDownloadKanjidicTo = null;
    private boolean mDownloadingKanjidic = false;

    private URL mDownloadTatoebaIndicesFrom = null;
    private File mDownloadTatoebaIndicesTo = null;
    private boolean mDownloadingTatoebaIndices = false;

    private URL mDownloadTatoebaSentencesFrom = null;
    private File mDownloadTatoebaSentencesTo = null;
    private boolean mDownloadingTatoebaSentences = false;

    private URL mDownloadKanjiVGFrom = null;
    private File mDownloadKanjiVGTo = null;
    private boolean mDownloadingKanjiVG = false;

    private boolean mDownloadInProgress = false;
    private boolean mCurrentlyDownloading = false;
    private boolean mParsing = false;

    private NotificationCompat.Builder mBuilder;
    private NotificationManager mNotifyManager = null;
    private Notification mNotification = null;
    private boolean mComplete = false;
    private boolean mNotEnoughSpace = false;

    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private boolean mRedelivery;
    private int mStartId;

    private class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            mStartId = msg.arg1;
            onHandleIntent();
        }
    }

    private class ServiceDownloadHandler extends ServiceHandler {
        public ServiceDownloadHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            try {
                downloadDictionaries();
            } catch (IOException e) {
                Log.w(LOG_TAG, "IOException caught while downloading: " + e.toString());
                stopSelf(mStartId);
            }
        }
    }

    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    private BroadcastReceiver mInternetReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager conn = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = conn.getActiveNetworkInfo();
            if (networkInfo == null) {
                Log.i(LOG_TAG, "Connection lost");
            } else {
                Log.i(LOG_TAG, "Connection Established");
                if (mDownloadInProgress && !mCurrentlyDownloading) {
                    Message msg = mServiceHandler.obtainMessage();
                    mServiceHandler = new ServiceDownloadHandler(mServiceLooper);
                    mServiceHandler.sendMessage(msg);
                }
            }
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();

        HandlerThread thread = new HandlerThread("IntentService[Dictionary_parser]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
        setIntentRedelivery(true);

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * Doenloads file from given URL. Creates new file or append old one.
     * 
     * @param url - to download from
     * @param outputFile File to save from URL
     * @return true if file was downloaded successfully else false
     * @throws IOException
     */
    private boolean downloadFile(URL url, File outputFile) throws IOException {
        mCurrentlyDownloading = true;
        BufferedInputStream input;
        OutputStream output;

        HttpURLConnection connection;
        connection = (HttpURLConnection) url.openConnection();
        connection.setRequestProperty("Accept-Encoding", "identity");
        connection.connect();
        long fileLength = connection.getContentLength();
        long total = 0;

        if (outputFile.exists()) {
            if ((outputFile.lastModified() + downloadExpireTime) < System.currentTimeMillis()) {
                CompressFolder.deleteDirectory(outputFile);
                output = new FileOutputStream(outputFile.getPath());
            } else {
                output = new FileOutputStream(outputFile.getPath(), true);
                total = outputFile.length();
                connection = (HttpURLConnection) url.openConnection();
                connection.setRequestProperty("Accept-Encoding", "identity");
                connection.setRequestProperty("Range", "bytes=" + total + "-");
                connection.connect();
            }

        } else {
            output = new FileOutputStream(outputFile.getPath());
        }

        // velikost souboru
        input = new BufferedInputStream(connection.getInputStream(), 1024);

        if (fileLength == -1) {
            mBuilder.setProgress(100, 0, false).setContentTitle(getString(R.string.dictionary_download_title))
                    .setContentText(getString(R.string.dictionary_download_in_progress)).setContentInfo("0%");

            mNotifyManager.notify(0, mBuilder.build());
        }

        byte data[] = new byte[1024];

        int count;
        int perc = 0;
        long lastUpdate = System.currentTimeMillis();
        try {
            while ((count = input.read(data)) != -1) {
                total += count;

                output.write(data, 0, count);
                // publishing the progress....
                if (fileLength != -1) {

                    long current = System.currentTimeMillis();
                    if (lastUpdate + 500 < current) {
                        int persPub = Math.round((((float) total / fileLength) * 100));
                        if (perc < persPub) {
                            lastUpdate = current;

                            mBuilder.setProgress(100, persPub, false).setContentInfo(persPub + "%");

                            mNotifyManager.notify(0, mBuilder.build());
                            perc = persPub;
                        }
                    }
                }
            }
        } catch (IOException ex) {
            Log.w(LOG_TAG, "ConnectionLost: " + ex);
            closeIOStreams(input, output);
            mCurrentlyDownloading = false;
            return false;
        }
        mCurrentlyDownloading = false;
        closeIOStreams(input, output);
        return true;

    }

    /**
     * Downloads dictionaries and launches parseDictionaries()
     * 
     * @throws IOException
     */
    private void downloadDictionaries() throws IOException {
        Log.i(LOG_TAG, "downloading JMDict");
        if (mDownloadingJMDict) {
            if (downloadFile(mDownloadJMDictFrom, mDownloadJMDictTo)) {
                mDownloadingJMDict = false;
                mDownloadingKanjidic = true;
            } else {
                return;
            }
        }
        Log.i(LOG_TAG, "downloading Kanjidic2");
        if (mDownloadingKanjidic) {
            mBuilder.setContentTitle(getString(R.string.dictionary_kanji_download_title)).setProgress(100, 0, false)
                    .setContentText(getString(R.string.dictionary_download_in_progress) + " (2/5)")
                    .setContentInfo("0%");

            mNotifyManager.notify(0, mBuilder.build());

            if (downloadFile(mDownloadKanjidicFrom, mDownloadKanjidicTo)) {
                mDownloadingKanjidic = false;
                mDownloadingTatoebaIndices = true;

                Log.i(LOG_TAG, "Downloading dictionary finished");

            } else {
                return;
            }
        }
        Log.i(LOG_TAG, "downloading Tatoeba japanese");
        if (mDownloadingTatoebaIndices) {
            mBuilder.setContentTitle(getString(R.string.dictionary_tatoeba_download_title))
                    .setProgress(100, 0, false)
                    .setContentText(getString(R.string.dictionary_download_in_progress) + " (3/5)")
                    .setContentInfo("0%");

            mNotifyManager.notify(0, mBuilder.build());

            if (downloadFile(mDownloadTatoebaIndicesFrom, mDownloadTatoebaIndicesTo)) {
                mDownloadingTatoebaIndices = false;
                mDownloadingTatoebaSentences = true;
                Log.i(LOG_TAG, "Downloading dictionary finished");

            } else {
                return;
            }
        }
        Log.i(LOG_TAG, "downloading Tatoeba translations");
        if (mDownloadingTatoebaSentences) {
            mBuilder.setContentTitle(getString(R.string.dictionary_tatoeba_download_title))
                    .setProgress(100, 0, false)
                    .setContentText(getString(R.string.dictionary_download_in_progress) + " (4/5)")
                    .setContentInfo("0%");

            mNotifyManager.notify(0, mBuilder.build());

            if (downloadFile(mDownloadTatoebaSentencesFrom, mDownloadTatoebaSentencesTo)) {
                mDownloadingTatoebaSentences = false;
                mDownloadingKanjiVG = true;

                Log.i(LOG_TAG, "Downloading dictionary finished");

            } else {
                return;
            }
        }
        Log.i(LOG_TAG, "downloading kanjivg strokes");
        if (mDownloadingKanjiVG) {
            mBuilder.setContentTitle(getString(R.string.dictionary_kanjivg_download_title))
                    .setProgress(100, 0, false)
                    .setContentText(getString(R.string.dictionary_download_in_progress) + " (5/5)")
                    .setContentInfo("0%");

            mNotifyManager.notify(0, mBuilder.build());

            if (downloadFile(mDownloadKanjiVGFrom, mDownloadKanjiVGTo)) {
                mDownloadingKanjiVG = false;
                mDownloadInProgress = false;

                Log.i(LOG_TAG, "Downloading dictionary finished");

            } else {
                return;
            }
        }

        if (!mDownloadInProgress && !mParsing) {
            try {
                mParsing = true;
                parseDictionaries();
            } catch (ParserConfigurationException e) {
                Log.e(LOG_TAG, "ParserConfigurationException exception occured: " + e.toString());
                stopSelf(mStartId);
            } catch (SAXException e) {
                Log.e(LOG_TAG, "SAXException exception occured: " + e.toString());
                stopSelf(mStartId);
            }
        }
    }

    /**
     * Parses downloaded dictionaries
     * 
     * @throws IOException
     * @throws ParserConfigurationException
     * @throws SAXException
     */
    private void parseDictionaries() throws IOException, ParserConfigurationException, SAXException {
        this.unregisterReceiver(mInternetReceiver);
        mInternetReceiver = null;

        mBuilder.setContentTitle(getString(R.string.parsing_downloaded_dictionary))
                .setContentText(getString(R.string.dictionary_parsing_in_progress)).setProgress(100, 100, false);

        mNotifyManager.notify(0, mBuilder.build());

        String japDictAbsolutePath = parseDictionary(mDownloadJMDictTo.getPath(), "jmdict");
        String japKanjiDictAbsolutePath = parseDictionary(mDownloadKanjidicTo.getPath(), "kanjidic");
        String tatoebaIndicesAbsolutePath = parseDictionary(mDownloadTatoebaIndicesTo.getPath(),
                "tatoeba_japanese");
        String tatoebaSentencesAbsolutePath = parseDictionary(mDownloadTatoebaSentencesTo.getPath(),
                "tatoeba_translations");
        String kanjiVGAbsolutePath = parseDictionary(mDownloadKanjiVGTo.getPath(), "kanjivg");

        Log.w(LOG_TAG, "restarting notificatiomn, setting ongoing false");
        mBuilder.setAutoCancel(true).setOngoing(false);

        mNotifyManager.notify(0, mBuilder.build());
        if (japDictAbsolutePath != null) {
            mComplete = true;
            serviceSuccessfullyDone(japDictAbsolutePath, japKanjiDictAbsolutePath, tatoebaIndicesAbsolutePath,
                    tatoebaSentencesAbsolutePath, kanjiVGAbsolutePath);
        } else {
            Log.e(LOG_TAG, "Parsing dictionary failed");
            stopSelf(mStartId);
        }
    }

    /**
     * Downloads dictionaries.
     */

    protected void onHandleIntent() {

        Log.i(LOG_TAG, "Creating parser service");

        Intent resultIntent = new Intent(getApplicationContext(), MainActivity.class);
        resultIntent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
        PendingIntent resultPendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, resultIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mBuilder = new NotificationCompat.Builder(this).setAutoCancel(false).setOngoing(true)
                .setContentTitle(getString(R.string.dictionary_download_title))
                .setContentText(getString(R.string.dictionary_download_in_progress) + " (1/5)")
                .setSmallIcon(R.drawable.ic_notification).setProgress(100, 0, false).setContentInfo("0%")
                .setContentIntent(resultPendingIntent);

        startForeground(0, mNotification);
        mNotifyManager.notify(0, mBuilder.build());
        File storage;
        if (MainActivity.canWriteExternalStorage()) {
            // external storage available
            storage = getExternalCacheDir();
        } else {
            storage = getCacheDir();
        }
        if (storage == null) {
            throw new IllegalStateException("External storage isn't accessible");
        }
        // free sapce controll
        StatFs stat = new StatFs(storage.getPath());
        long bytesAvailable;
        if (Build.VERSION.SDK_INT < 18) {
            bytesAvailable = (long) stat.getBlockSize() * (long) stat.getAvailableBlocks();
        } else {
            bytesAvailable = stat.getAvailableBytes();
        }
        long megAvailable = bytesAvailable / 1048576;
        Log.d(LOG_TAG, "Megs free :" + megAvailable);
        if (megAvailable < 140) {
            mInternetReceiver = null;
            mNotEnoughSpace = true;
            stopSelf(mStartId);
            return;
        }

        this.registerReceiver(mInternetReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));

        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
        boolean english = sharedPrefs.getBoolean("language_english", false);
        boolean french = sharedPrefs.getBoolean("language_french", false);
        boolean dutch = sharedPrefs.getBoolean("language_dutch", false);
        boolean german = sharedPrefs.getBoolean("language_german", false);
        boolean russian = sharedPrefs.getBoolean("language_russian", false);
        if (!english && !french && !dutch && !german && !russian) {
            Log.i(LOG_TAG, "Setting english as only translation language");
            SharedPreferences.Editor editor_lang = sharedPrefs.edit();
            editor_lang.putBoolean("language_english", true);
            editor_lang.commit();
        }

        String dictionaryPath;
        String kanjiDictPath;

        URL url;
        try {
            url = new URL(ParserService.DICTIONARY_PATH);
        } catch (MalformedURLException ex) {
            Log.e(LOG_TAG, "Error: creating url for downloading dictionary");
            return;
        }

        try {

            dictionaryPath = storage.getPath() + File.separator + "dictionary.zip";
            File outputFile = new File(dictionaryPath);
            if (outputFile.exists()) {
                outputFile.delete();
            }

            mDownloadJMDictFrom = url;
            mDownloadJMDictTo = outputFile;
            mDownloadingJMDict = true;
            mDownloadInProgress = true;

            // downloading kanjidict
            url = null;
            try {
                url = new URL(ParserService.KANJIDICT_PATH);
            } catch (MalformedURLException ex) {
                Log.e(LOG_TAG, "Error: creating url for downloading kanjidict2");
            }
            if (url != null) {
                kanjiDictPath = storage.getPath() + File.separator + "kanjidict.zip";
                File fileKanjidict = new File(kanjiDictPath);
                if (fileKanjidict.exists()) {
                    fileKanjidict.delete();
                }
                mDownloadingKanjidic = false;
                mDownloadKanjidicFrom = url;
                mDownloadKanjidicTo = fileKanjidict;
            }

            mDownloadTatoebaIndicesFrom = new URL(ParserService.TATOEBA_INDICES_PATH);
            mDownloadTatoebaIndicesTo = new File(storage, "tatoeba-japanese.zip");
            if (mDownloadTatoebaIndicesTo.exists()) {
                mDownloadTatoebaIndicesTo.delete();
            }

            mDownloadTatoebaSentencesFrom = new URL(ParserService.TATOEBA_SENTENCES_PATH);
            mDownloadTatoebaSentencesTo = new File(storage, "tatoeba-translation.zip");
            if (mDownloadTatoebaSentencesTo.exists()) {
                mDownloadTatoebaSentencesTo.delete();
            }

            mDownloadKanjiVGFrom = new URL(ParserService.KANJIVG_PATH);
            mDownloadKanjiVGTo = new File(storage, "kanjivg.zip");
            if (mDownloadKanjiVGTo.exists()) {
                mDownloadKanjiVGTo.delete();
            }

            downloadDictionaries();

        } catch (MalformedURLException e) {
            Log.e(LOG_TAG, "MalformedURLException wrong format of URL: " + e.toString());
            stopSelf(mStartId);
        } catch (IOException e) {
            Log.e(LOG_TAG, "IOException downloading interrupted: " + e.toString());
            stopSelf(mStartId);
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(LOG_TAG, "Exception: " + e.toString());
            stopSelf(mStartId);
        }

    }

    /**
     * Parse downloaded JMdict dictionary.
     * 
     * @param pathDownloaded to the dictionary gziped file
      * @param dictionaryName dictionary name
     * @return path to lucene folder for jmdict
     * @throws IOException
     * @throws ParserConfigurationException
     * @throws SAXException
     */
    private String parseDictionary(String pathDownloaded, String dictionaryName)
            throws IOException, ParserConfigurationException, SAXException {

        Log.i(LOG_TAG, "Parsing dictionary - start");

        File downloadedFile = new File(pathDownloaded);
        File externalDir = getExternalCacheDir() == null ? getCacheDir() : getExternalCacheDir();
        String indexFile = externalDir.getAbsolutePath() + File.separator + dictionaryName;
        File file = new File(indexFile);
        boolean renameFolder = false;
        if (!file.mkdir()) {
            String indexFileTempPath = indexFile + "_temp";
            file = new File(indexFileTempPath);
            renameFolder = true;
            if (!file.mkdir()) {
                deleteDirectory(file);
                file.mkdir();
            }
        }

        CompressFolder.unzip(downloadedFile, file);
        downloadedFile.delete();
        if (renameFolder) {
            Log.i(LOG_TAG, "Parsing dictionary - rename folders");
            File directory = new File(indexFile);
            deleteDirectory(directory);
            if (file.renameTo(directory)) {
                Log.i(LOG_TAG, "Parsing dictionary - folder renamed");
                file = directory;
            }
        }
        return file.getAbsolutePath();

    }

    /**
     * Called when parsing was succesfully done. Sets shared preferences and
     * broadcast downloadingDictinaryServiceDone intent.
     * 
     * @param jmdictPath path to JMdict dictionary
     * @param kanjiDictPath path to kanjidict2 dictionary
     */
    private void serviceSuccessfullyDone(String jmdictPath, String kanjiDictPath, String tatoebaIndicesPath,
            String tatoebaSentencesPath, String kanjiVgPath) {
        Log.i(LOG_TAG, "Parsing dictionary - parsing succesfully done, saving preferences");
        SharedPreferences settings = getSharedPreferences(DICTIONARY_PREFERENCES, 0);
        SharedPreferences.Editor editor = settings.edit();
        Log.i(LOG_TAG, "Dictionary path: " + jmdictPath);
        Log.i(LOG_TAG, "KanjiDict path: " + kanjiDictPath);
        Log.i(LOG_TAG, "tatoeba indices  path: " + tatoebaIndicesPath);
        Log.i(LOG_TAG, "tatoeba sentences path: " + tatoebaSentencesPath);
        Log.i(LOG_TAG, "kanjivg path: " + kanjiVgPath);
        editor.putString(Const.PREF_JMDICT_PATH, jmdictPath);
        editor.putString(Const.PREF_KANJIDIC_PATH, kanjiDictPath);
        editor.putString(Const.PREF_TATOEBA_INDICES_PATH, tatoebaIndicesPath);
        editor.putString(Const.PREF_TATOEBA_SENTENCES_PATH, tatoebaSentencesPath);
        editor.putString(Const.PREF_KANJIVG_PATH, kanjiVgPath + "/kanji");
        Date date = new Date();
        editor.putLong("dictionaryLastUpdate", date.getTime());
        editor.commit();

        Log.i(LOG_TAG, "Parsing dictionary - preferences saved");
        Intent intent = new Intent("downloadingDictinaryServiceDone");
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
        stopSelf(mStartId);
    }

    /**
     * If service wasn't done succesfully changes
     * notification and broadcasts serviceCanceled intent.
     */
    @Override
    public void onDestroy() {
        super.onDestroy();

        stopForeground(true);
        if (mInternetReceiver != null) {
            this.unregisterReceiver(mInternetReceiver);
        }
        mBuilder.setAutoCancel(true).setOngoing(false).setProgress(0, 0, false).setContentText("")
                .setContentInfo("");
        if (!mComplete) {
            Log.w(LOG_TAG, "restarting notificatiomn, setting ongoing false");
            mBuilder.setContentTitle(getString(R.string.dictionary_download_interrupted));

            Intent intent = new Intent("serviceCanceled");
            LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
            Log.w(LOG_TAG, "Service ending none complete");
        } else {
            mBuilder.setContentTitle(getString(R.string.dictionary_download_complete));
            mBuilder.setContentText(getString(R.string.dictionary_download_complete_text));
        }
        if (mNotEnoughSpace) {
            mBuilder.setContentTitle(getString(R.string.dictionary_download_interrupted));
            mBuilder.setContentText(getString(R.string.dictionary_not_enough_space));
        }
        mNotifyManager.notify(0, mBuilder.build());
        mServiceLooper.quit();
    }

    /**
     * Tries to close IO streams.
     */
    private void closeIOStreams(InputStream input, OutputStream output) {
        if (input != null) {
            try {
                input.close();
            } catch (IOException e) {
                Log.w(LOG_TAG, "Closing input causded excaption");
            }
        }
        if (output != null) {
            try {
                output.close();
            } catch (IOException e) {
                Log.w(LOG_TAG, "Closing output causded excaption");
            }
        }

    }

    /**
     * Deletes given directory
     * 
     * @param directory directory to be deleted
     * @return true on succes
     */
    static private boolean deleteDirectory(File directory) {
        if (directory.exists()) {
            File[] files = directory.listFiles();
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteDirectory(file);
                } else {
                    file.delete();
                }
            }
        }
        return (directory.delete());
    }

}