com.open.file.manager.CutCopyService.java Source code

Java tutorial

Introduction

Here is the source code for com.open.file.manager.CutCopyService.java

Source

/*******************************************************************************
 * Copyright (c) 2013 Michele Corazza.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Credits:
 *    Actionbarsherlock library: for the fragment support
 *    Oxygen team: for the gorgeous icons
 ******************************************************************************/
package com.open.file.manager;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.StatFs;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.RemoteViews;

public class CutCopyService extends IntentService {

    public CutCopyService() {
        super("CutCopyService");
    }

    private int currentaction;
    private File targetfolder;
    private ArrayList<String> filelist;
    private Notification cutcopynotification;
    public NotificationManager cutcopymanager;
    private NotificationCompat.Builder cutcopybuilder;
    private RemoteViews progressview;
    private FileCopyTree tree;
    private ArrayList<FileDuplicate> duplicates;
    private static int id;
    private static int completeid = 0;
    private long progressbytes;
    private int progresspercent;
    private long totalbytes;
    public static Handler mHandler;
    static int currentfileind;
    public final int[] actions = new int[] { R.string.copy, R.string.move };
    public final int[] actioning = new int[] { R.string.copyger, R.string.moveger };
    public final int[] actionspast = new int[] { R.string.copypast, R.string.movepast };
    static String actiongerund;
    PendingIntent contentIntent;

    /**
     * Proceed to cut/copy file(s) if there is no duplicate(s)
     */
    private void performCutCopy() {
        FileCopyNode current;
        while (currentfileind < tree.children.size()) {
            try {
                current = tree.children.get(currentfileind);
                if (current.duplicate != null && duplicates == null) {
                    String waitingdup = getResources().getString(R.string.waitingduplicate);
                    cutcopynotification.contentView.setTextViewText(R.id.progresstext, waitingdup);
                    cutcopymanager.notify(id, cutcopynotification);
                    Looper.loop();
                }
                performOperation(tree.children.get(currentfileind));
                currentfileind++;
            } catch (Exception e) {
                notifyError(R.string.unknownerror);
                e.printStackTrace();
            }
            currentfileind++;
        }
        finish();
    }

    /**
     * Notify some error has occurred with notification
     * @param errorRes resource to show
     */
    private void notifyError(int errorRes) {
        String errformat, errstring;
        stopForeground(true);
        errformat = getResources().getString(errorRes);
        errstring = String.format(errformat, getResources().getString(actions[currentaction]));
        cutcopynotification = new Notification();
        cutcopynotification.contentView = new RemoteViews(getApplicationContext().getPackageName(),
                R.layout.errornot);
        cutcopynotification.contentView.setTextViewText(R.id.errortext, errstring);
        cutcopynotification.contentIntent = contentIntent;
        cutcopynotification.icon = R.drawable.error;
        cutcopymanager.notify(completeid, cutcopynotification);
    }

    /**
     * Checks weither there's enough space to perform the operation
     * @param current
     * @return
     */
    private boolean notEnoughSpace(FileCopyNode current) {
        StatFs targetfs = new StatFs(current.dstFile.getParent());
        return current.size > (long) targetfs.getAvailableBlocks() * (long) targetfs.getBlockSize();
    }

    private void finish() {
        NotificationCompat.Builder finishbuilder = new NotificationCompat.Builder(this);
        String completed = getResources().getString(R.string.completed);
        String actionpast = getResources().getString(actionspast[currentaction]);
        String finished = getResources().getString(R.string.succesfulcopy);
        finished = String.format(finished, FileOperations.gethumansize(totalbytes), actionpast);
        finishbuilder.setContentText(finished);
        finishbuilder.setContentTitle(completed);
        finishbuilder.setSmallIcon(R.drawable.complete);
        finishbuilder.setContentIntent(contentIntent);
        cutcopymanager.notify(completeid, finishbuilder.build());
        MainActivity.acthandler.sendEmptyMessage(Consts.MSG_FINISHED);
        stopForeground(true);
        return;
    }

    /**
     * Show progress in notification
     */
    private void updateProgress() {
        String progressstring;
        if (progresspercent != (int) ((100 * progressbytes) / totalbytes)) {
            progresspercent = (int) ((100 * progressbytes) / totalbytes);
            cutcopynotification.contentView.setProgressBar(R.id.progressBar, 100, progresspercent, false);
            progressstring = FileOperations.gethumansize(progressbytes) + "/"
                    + FileOperations.gethumansize(totalbytes);
            cutcopynotification.contentView.setTextViewText(R.id.textprogress, progressstring);
            cutcopymanager.notify(id, cutcopynotification);
        }
    }

    /**
     * Update duplicates in FileCopyNodes with duplicates received from
     * the activity
     * @param newduplic duplicates received
     * @param files file nodes to update
     */
    void updateDuplicates(ArrayList<FileDuplicate> newduplic, List<FileCopyNode> files) {
        FileDuplicate currentdup;
        int i, j = 0;
        for (i = 0; i < files.size(); i++) {
            FileCopyNode currentfile = files.get(i);
            if (j < newduplic.size()) {
                currentdup = newduplic.get(j);
            } else {
                currentdup = null;
            }
            if (currentfile.duplicate != null && currentdup != null) {
                currentfile.duplicate = currentdup;
                j++;
                if (currentfile.children.size() > 0 && currentdup.childDuplicates != null) {
                    updateDuplicates(currentdup.childDuplicates, currentfile.children);
                }
            }
        }

    }

    /**
     * Cut or copy file
     * @param filenode node to process
     * @throws IOException
     */
    private void performOperation(FileCopyNode filenode) throws IOException {
        if (filenode.duplicate != null) {
            if (!filenode.duplicate.overwrite) {
                totalbytes -= filenode.size;
                updateProgress();
                return;
            } else {
                //dir/dir conflict, continue transferring directory content
                if (filenode.duplicate.type == Consts.CONFLICT_DIR_DIR) {
                    for (int i = 0; i < filenode.children.size(); i++) {
                        performOperation(filenode.children.get(i));
                    }
                    return;
                }
                // file/dir conflict, rename destination
                if (filenode.duplicate.type == Consts.CONFLICT_FILE_DIR) {
                    filenode.dstFile = new File(filenode.dstFile.getParent(), filenode.duplicate.newname);
                }
                // file/file conflict, remove destination
                else {
                    filenode.dstFile.delete();
                }
            }
        }
        if (filenode.srcFile.isDirectory()) {
            filenode.dstFile.mkdir();
            for (int i = 0; i < filenode.children.size(); i++) {
                performOperation(filenode.children.get(i));
            }
            return;
        }
        if (currentaction == 0) {
            copy(filenode, true);
        } else {
            if (renameSuccessful(filenode.srcFile, filenode.dstFile)) {
                progressbytes += filenode.size;
                updateProgress();
            } else {
                copy(filenode, false);
            }
        }
    }

    /**
     * Try to rename file to move it
     * @param src
     * @param dst
     * @return true if it worked, false otherwise
     */
    private boolean renameSuccessful(File src, File dst) {
        return src.renameTo(dst);
    }

    /**
     * Copy files
     * @param filenode node to process
     * @param keeporiginal
     * @throws IOException
     */
    private void copy(FileCopyNode filenode, boolean keeporiginal) throws IOException {
        if (notEnoughSpace(filenode)) {
            notifyError(R.string.notenoughspace);
            stopSelf();
        }
        if (filenode.srcFile.length() == 0) {
            filenode.dstFile.createNewFile();
            updateProgress();
            return;
        }
        InputStream in = new FileInputStream(filenode.srcFile);
        OutputStream out = new FileOutputStream(filenode.dstFile);
        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
            progressbytes += len;
            updateProgress();
        }
        in.close();
        out.close();
        if (!keeporiginal) {
            filenode.srcFile.delete();
        }
    }

    void sendDuplicateMessage() {
        Message dupmsg = Message.obtain();
        dupmsg.what = Consts.MSG_DUPLICATES;
        Bundle dupdata = new Bundle();
        dupdata.putParcelableArrayList("duplicates", tree.duplicates);
        dupmsg.setData(dupdata);
        MainActivity.acthandler.sendMessage(dupmsg);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        progressview = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbarlayout);

        currentaction = intent.getIntExtra("action", 0);
        filelist = intent.getStringArrayListExtra("filelist");
        targetfolder = new File(intent.getStringExtra("targetfolder"));
        tree = new FileCopyTree(filelist, targetfolder);
        duplicates = null;
        currentfileind = 0;
        progressbytes = 0;
        progresspercent = 0;
        totalbytes = tree.size;
        mHandler = new dupresponcehandler(this);
        if (tree.duplicates.size() != 0) {
            sendDuplicateMessage();
        }
        id = 1;
        completeid = (completeid + 2) % Integer.MAX_VALUE;
        cutcopymanager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        cutcopybuilder = new NotificationCompat.Builder(this);
        // cutcopybuilder.setProgress(100, 0, false);

        Intent notificationIntent = new Intent(this, MainActivity.class);
        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
        cutcopybuilder
                .setContent(new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbarlayout));
        cutcopybuilder.setSmallIcon(R.drawable.notifyicon);
        actiongerund = getResources().getString(actioning[currentaction]);
        cutcopybuilder.setContentTitle(actiongerund + " files");
        cutcopybuilder.setContentIntent(contentIntent);
        cutcopynotification = cutcopybuilder.build();
        cutcopynotification.contentView = progressview;
        cutcopynotification.contentView.setProgressBar(R.id.progressBar, 100, 0, false);
        cutcopynotification.contentView.setTextViewText(R.id.progresstext, actiongerund + " files");
        cutcopymanager.notify(id, cutcopynotification);
        startForeground(id, cutcopynotification);
        performCutCopy();
    }

    static class dupresponcehandler extends Handler {
        WeakReference<CutCopyService> mservice;

        dupresponcehandler(CutCopyService service) {
            mservice = new WeakReference<CutCopyService>(service);
        }

        @Override
        public void handleMessage(Message msg) {
            CutCopyService currentservice = mservice.get();
            if (mservice != null && currentservice != null) {
                if (msg.what == Consts.MSG_DUPLICATES) {
                    currentservice.duplicates = msg.getData().getParcelableArrayList("duplicates");
                    currentservice.tree.duplicates = currentservice.duplicates;
                    currentservice.updateDuplicates(currentservice.duplicates, currentservice.tree.children);
                    currentservice.cutcopynotification.contentView.setTextViewText(R.id.progresstext,
                            actiongerund + " files");
                    currentservice.cutcopymanager.notify(id, currentservice.cutcopynotification);
                    currentservice.performCutCopy();
                }
                if (msg.what == Consts.MSG_ACTIVITYRESTART) {
                    if (currentservice.duplicates == null) {
                        Log.d("send", "duplicates");
                        mservice.get().sendDuplicateMessage();
                    }
                }
            }
        }
    }
}