com.filemanager.free.services.CopyService.java Source code

Java tutorial

Introduction

Here is the source code for com.filemanager.free.services.CopyService.java

Source

/*
 * Copyright (c) 2016. by Hoang Hiep (hoanghiep8899@gmail.com)
 * This file CopyService.java is part of File Manager
 * Create at 3/6/16 2:19 PM
 * 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 com.filemanager.free.services;

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.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import com.filemanager.free.ProgressListener;
import com.filemanager.free.R;
import com.filemanager.free.RegisterCallback;
import com.filemanager.free.activities.MainActivity;
import com.filemanager.free.filesystem.BaseFile;
import com.filemanager.free.services.FileVerifier.FileVerifierInterface;
import com.filemanager.free.utils.DataPackage;
import com.filemanager.free.utils.Futils;
import com.filemanager.free.filesystem.HFile;
import com.filemanager.free.filesystem.RootHelper;
import com.stericson.RootTools.RootTools;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class CopyService extends Service {
    HashMap<Integer, Boolean> hash = new HashMap<>();
    public HashMap<Integer, DataPackage> hash1 = new HashMap<>();
    boolean rootmode;
    NotificationManager mNotifyManager;
    NotificationCompat.Builder mBuilder;
    Context c;
    Futils utils;

    @Override
    public void onCreate() {
        c = getApplicationContext();
        utils = new Futils();
        SharedPreferences Sp = PreferenceManager.getDefaultSharedPreferences(this);
        rootmode = Sp.getBoolean("rootmode", false);
        registerReceiver(receiver3, new IntentFilter("copycancel"));
    }

    boolean foreground = true;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) throws NullPointerException {
        Bundle b = new Bundle();
        ArrayList<BaseFile> files = intent.getParcelableArrayListExtra("FILE_PATHS");
        String FILE2 = intent.getStringExtra("COPY_DIRECTORY");
        int mode = intent.getIntExtra("MODE", 0);
        mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        b.putInt("id", startId);
        Intent notificationIntent = new Intent(this, MainActivity.class);
        notificationIntent.setAction(Intent.ACTION_MAIN);
        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        notificationIntent.putExtra("openprocesses", true);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
        mBuilder = new NotificationCompat.Builder(c);
        mBuilder.setContentIntent(pendingIntent);
        mBuilder.setContentTitle(getResources().getString(R.string.copying))

                .setSmallIcon(R.drawable.ic_content_copy_white_36dp);
        if (foreground) {
            startForeground(Integer.parseInt("456" + startId), mBuilder.build());
            foreground = false;
        }
        b.putBoolean("move", intent.getBooleanExtra("move", false));
        b.putString("FILE2", FILE2);
        b.putInt("MODE", mode);
        b.putParcelableArrayList("files", files);
        hash.put(startId, true);
        DataPackage intent1 = new DataPackage();
        intent1.setName(files.get(0).getName());
        intent1.setTotal(0);
        intent1.setDone(0);
        intent1.setId(startId);
        intent1.setP1(0);
        intent1.setP2(0);
        intent1.setMove(intent.getBooleanExtra("move", false));
        intent1.setCompleted(false);
        hash1.put(startId, intent1);
        //going async
        new DoInBackground().execute(b);

        // If we get killed, after returning from here, restart
        return START_STICKY;
    }

    ProgressListener progressListener;

    public void onDestroy() {
        this.unregisterReceiver(receiver3);
    }

    public class DoInBackground extends AsyncTask<Bundle, Void, Integer> {
        ArrayList<BaseFile> files;
        boolean move;
        FileVerifier fileVerifier;
        Copy copy;

        public DoInBackground() {
        }

        protected Integer doInBackground(Bundle... p1) {
            String FILE2 = p1[0].getString("FILE2");
            int id = p1[0].getInt("id");
            files = p1[0].getParcelableArrayList("files");
            move = p1[0].getBoolean("move");
            copy = new Copy();
            copy.execute(id, files, FILE2, move, p1[0].getInt("MODE"));

            // TODO: Implement this method
            return id;
        }

        @Override
        public void onPostExecute(Integer b) {
            publishResults("", 0, 0, b, 0, 0, true, move);
            if (fileVerifier != null && fileVerifier.isRunning()) {
                while (fileVerifier.isRunning()) {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            generateNotification(copy.failedFOps, move);
            Intent intent = new Intent("loadlist");
            sendBroadcast(intent);
            hash.put(b, false);
            boolean stop = true;
            for (int a : hash.keySet()) {
                if (hash.get(a))
                    stop = false;
            }
            if (!stop)
                stopSelf(b);
            else
                stopSelf();

        }

        class Copy {

            long totalBytes = 0L, copiedBytes = 0L;
            boolean calculatingTotalSize = false;
            ArrayList<HFile> failedFOps;
            ArrayList<BaseFile> toDelete;
            boolean copy_successful;

            public Copy() {
                copy_successful = true;
                fileVerifier = new FileVerifier(c, rootmode, new FileVerifierInterface() {
                    @Override
                    public void addFailedFile(HFile a) {
                        failedFOps.add(a);
                    }

                    @Override
                    public boolean contains(String path) {
                        for (HFile a : failedFOps)
                            if (a.getPath().equals(path))
                                return true;
                        return false;
                    }

                    @Override
                    public boolean containsDirectory(String path) {
                        for (HFile a : failedFOps)
                            if (a.getPath().contains(path))
                                return true;
                        return false;
                    }

                    @Override
                    public void setCopySuccessful(boolean b) {
                        copy_successful = b;
                    }
                });
                failedFOps = new ArrayList<>();
                toDelete = new ArrayList<>();
            }

            long getTotalBytes(final ArrayList<BaseFile> files) {
                calculatingTotalSize = true;
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        long totalBytes = 0l;
                        try {
                            for (int i = 0; i < files.size(); i++) {
                                HFile f1 = (files.get(i));
                                if (f1.isDirectory()) {
                                    totalBytes = totalBytes + f1.folderSize();
                                } else {
                                    totalBytes = totalBytes + f1.length();
                                }
                            }
                        } catch (Exception e) {
                        }
                        Copy.this.totalBytes = totalBytes;
                        calculatingTotalSize = false;
                    }
                }).run();

                return totalBytes;
            }

            public void execute(int id, final ArrayList<BaseFile> files, final String FILE2, final boolean move,
                    int mode) {
                if (utils.checkFolder((FILE2), c) == 1) {
                    getTotalBytes(files);
                    for (int i = 0; i < files.size(); i++) {
                        BaseFile f1 = (files.get(i));
                        Log.e("Copy", "basefile\t" + f1.getPath());
                        try {

                            if (hash.get(id)) {
                                if (!f1.isSmb() && !new File(files.get(i).getPath()).canRead() && rootmode) {
                                    copyRoot(files.get(i).getPath(), files.get(i).getName(), FILE2, move);
                                    continue;
                                }
                                HFile hFile = new HFile(mode, FILE2, files.get(i).getName(), f1.isDirectory());
                                copyFiles((f1), hFile, id, move);
                            } else {
                                break;
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                            Log.e("Copy", "Got exception checkout");

                            failedFOps.add(files.get(i));
                            for (int j = i + 1; j < files.size(); j++)
                                failedFOps.add(files.get(j));
                            break;
                        }
                    }

                } else if (rootmode) {
                    boolean m = true;
                    for (int i = 0; i < files.size(); i++) {
                        String path = files.get(i).getPath();
                        String name = files.get(i).getName();
                        copyRoot(path, name, FILE2, move);
                        if (checkFiles(new HFile(files.get(i).getMode(), path),
                                new HFile(HFile.ROOT_MODE, FILE2 + "/" + name))) {
                            failedFOps.add(files.get(i));
                        }
                    }
                    if (move && m) {
                        ArrayList<BaseFile> toDelete = new ArrayList<>();
                        for (BaseFile a : files) {
                            if (!failedFOps.contains(a))
                                toDelete.add(a);
                        }
                        new DeleteTask(getContentResolver(), c).execute((toDelete));
                    }

                } else {
                    for (BaseFile f : files)
                        failedFOps.add(f);
                }
            }

            boolean copyRoot(String path, String name, String FILE2, boolean move) {
                boolean b = RootTools.copyFile(RootHelper.getCommandLineString(path),
                        RootHelper.getCommandLineString(FILE2) + "/" + name, true, true);
                if (!b && path.contains("/0/"))
                    b = RootTools.copyFile(RootHelper.getCommandLineString(path.replace("/0/", "/legacy/")),
                            RootHelper.getCommandLineString(FILE2) + "/" + name, true, true);
                utils.scanFile(FILE2 + "/" + name, c);
                return b;
            }

            private void copyFiles(final BaseFile sourceFile, final HFile targetFile, final int id,
                    final boolean move) throws IOException {
                Log.e("Copy", sourceFile.getPath());
                if (sourceFile.isDirectory()) {
                    if (!hash.get(id))
                        return;
                    if (!targetFile.exists())
                        targetFile.mkdir(c);
                    if (!targetFile.exists()) {
                        Log.e("Copy", "cant make dir");
                        failedFOps.add(sourceFile);
                        copy_successful = false;
                        return;
                    }
                    targetFile.setLastModified(sourceFile.lastModified());
                    if (!hash.get(id))
                        return;
                    ArrayList<BaseFile> filePaths = sourceFile.listFiles(false);
                    for (BaseFile file : filePaths) {
                        HFile destFile = new HFile(targetFile.getMode(), targetFile.getPath(), file.getName(),
                                file.isDirectory());
                        copyFiles(file, destFile, id, move);
                    }
                    if (!hash.get(id))
                        return;
                    fileVerifier.add(new FileBundle(sourceFile, targetFile, move));
                } else {
                    if (!hash.get(id))
                        return;
                    long size = sourceFile.length();
                    InputStream in = sourceFile.getInputStream();
                    OutputStream out = targetFile.getOutputStream(c);
                    if (in == null || out == null) {
                        Log.e("Copy", "streams null");
                        failedFOps.add(sourceFile);
                        copy_successful = false;
                        return;
                    }
                    if (!hash.get(id))
                        return;
                    copy(in, out, size, id, sourceFile.getName(), move);
                    fileVerifier.add(new FileBundle(sourceFile, targetFile, move));
                }
            }

            long time = System.nanoTime() / 500000000;
            AsyncTask asyncTask;

            void calculateProgress(final String name, final long fileBytes, final int id, final long size,
                    final boolean move) {
                if (asyncTask != null && asyncTask.getStatus() == AsyncTask.Status.RUNNING)
                    asyncTask.cancel(true);
                asyncTask = new AsyncTask<Void, Void, Void>() {
                    int p1, p2;

                    @Override
                    protected Void doInBackground(Void... voids) {
                        p1 = (int) ((copiedBytes / (float) totalBytes) * 100);
                        p2 = (int) ((fileBytes / (float) size) * 100);
                        if (calculatingTotalSize)
                            p1 = 0;
                        return null;
                    }

                    @Override
                    public void onPostExecute(Void v) {
                        publishResults(name, p1, p2, id, totalBytes, copiedBytes, false, move);
                    }
                }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
            }

            void copy(InputStream stream, OutputStream outputStream, long size, int id, String name, boolean move)
                    throws IOException {
                long fileBytes = 0l;
                BufferedInputStream in = new BufferedInputStream(stream);
                BufferedOutputStream out = new BufferedOutputStream(outputStream);
                byte[] buffer = new byte[1024 * 60];
                int length;
                //copy the file content in bytes
                while ((length = in.read(buffer)) > 0) {
                    boolean b = hash.get(id);
                    if (b) {
                        out.write(buffer, 0, length);
                        copiedBytes += length;
                        fileBytes += length;
                        long time1 = System.nanoTime() / 500000000;
                        if (((int) time1) > ((int) (time))) {
                            calculateProgress(name, fileBytes, id, size, move);
                            time = System.nanoTime() / 500000000;
                        }

                    } else {
                        break;
                    }
                }
                in.close();
                out.close();
                stream.close();
                outputStream.close();
            }

        }
    }

    void generateNotification(ArrayList<HFile> failedOps, boolean move) {
        if (failedOps.size() == 0)
            return;
        mNotifyManager.cancelAll();
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(c);
        mBuilder.setContentTitle("Operation Unsuccessful");
        mBuilder.setContentText("Some files weren't %s successfully".replace("%s", move ? "moved" : "copied"));
        Intent intent = new Intent(this, MainActivity.class);
        intent.putExtra("failedOps", failedOps);
        intent.putExtra("move", move);
        PendingIntent pIntent = PendingIntent.getActivity(this, 101, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        mBuilder.setContentIntent(pIntent);
        mBuilder.setSmallIcon(R.drawable.ic_content_copy_white_36dp);
        mNotifyManager.notify(741, mBuilder.build());
        intent = new Intent("general_communications");
        intent.putExtra("failedOps", failedOps);
        intent.putExtra("move", move);
        sendBroadcast(intent);
    }

    private void publishResults(String a, int p1, int p2, int id, long total, long done, boolean b, boolean move) {
        if (hash.get(id)) {
            //notification
            mBuilder.setProgress(100, p1, false);
            mBuilder.setOngoing(true);
            int title = R.string.copying;
            if (move)
                title = R.string.moving;
            mBuilder.setContentTitle(utils.getString(c, title));
            mBuilder.setContentText(new File(a).getName() + " " + utils.readableFileSize(done) + "/"
                    + utils.readableFileSize(total));
            int id1 = Integer.parseInt("456" + id);
            mNotifyManager.notify(id1, mBuilder.build());
            if (p1 == 100 || total == 0) {
                mBuilder.setContentTitle("Copy completed");
                if (move)
                    mBuilder.setContentTitle("Move Completed");
                mBuilder.setContentText("");
                mBuilder.setProgress(0, 0, false);
                mBuilder.setOngoing(false);
                mBuilder.setAutoCancel(true);
                mNotifyManager.notify(id1, mBuilder.build());
                publishCompletedResult(id, id1);
            }
            //for processviewer
            DataPackage intent = new DataPackage();
            intent.setName(a);
            intent.setTotal(total);
            intent.setDone(done);
            intent.setId(id);
            intent.setP1(p1);
            intent.setP2(p2);
            intent.setMove(move);
            intent.setCompleted(b);
            hash1.put(id, intent);
            try {
                if (progressListener != null) {
                    progressListener.onUpdate(intent);
                    if (b)
                        progressListener.refresh();
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        } else
            publishCompletedResult(id, Integer.parseInt("456" + id));
    }

    public void publishCompletedResult(int id, int id1) {
        try {
            mNotifyManager.cancel(id1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //check if copy is successful
    boolean checkFiles(HFile hFile1, HFile hFile2) {
        if (RootHelper.isDirectory(hFile1.getPath(), rootmode, 5)) {
            if (RootHelper.fileExists(hFile2.getPath()))
                return false;
            ArrayList<BaseFile> baseFiles = RootHelper.getFilesList(hFile1.getPath(), true, true, null);
            if (baseFiles.size() > 0) {
                boolean b = true;
                for (BaseFile baseFile : baseFiles) {
                    if (!checkFiles(new HFile(baseFile.getMode(), baseFile.getPath()),
                            new HFile(hFile2.getMode(), hFile2.getPath() + "/" + (baseFile.getName()))))
                        b = false;
                }
                return b;
            }
            return RootHelper.fileExists(hFile2.getPath());
        } else {
            ArrayList<BaseFile> baseFiles = RootHelper.getFilesList(hFile1.getParent(), true, true, null);
            int i = -1;
            int index = -1;
            for (BaseFile b : baseFiles) {
                i++;
                if (b.getPath().equals(hFile1.getPath())) {
                    index = i;
                    break;
                }
            }
            ArrayList<BaseFile> baseFiles1 = RootHelper.getFilesList(hFile1.getParent(), true, true, null);
            int i1 = -1;
            int index1 = -1;
            for (BaseFile b : baseFiles1) {
                i1++;
                if (b.getPath().equals(hFile1.getPath())) {
                    index1 = i1;
                    break;
                }
            }
            if (baseFiles.get(index).getSize() == baseFiles1.get(index1).getSize())
                return true;
            else
                return false;
        }
    }

    private BroadcastReceiver receiver3 = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            //cancel operation
            hash.put(intent.getIntExtra("id", 1), false);
        }
    };
    //bind with processviewer
    RegisterCallback registerCallback = new RegisterCallback.Stub() {
        @Override
        public void registerCallBack(ProgressListener p) throws RemoteException {
            progressListener = p;
        }

        @Override
        public List<DataPackage> getCurrent() throws RemoteException {
            List<DataPackage> dataPackages = new ArrayList<>();
            for (int i : hash1.keySet()) {
                dataPackages.add(hash1.get(i));
            }
            return dataPackages;
        }
    };

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return registerCallback.asBinder();
    }
}