/** * DiskUsage - displays sdcard usage on android. * Copyright (C) 2008 Ivan Volosyuk * * 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 2 * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package com.google.android.diskusage; import java.io.File; import com.google.android.diskusage.datasource.DataSource; import com.google.android.diskusage.entity.FileSystemEntry; import com.google.android.diskusage.entity.FileSystemPackage; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.DialogInterface.OnDismissListener; import android.content.Intent; import android.net.Uri; import android.util.Log; import android.widget.Toast; public class BackgroundDelete extends Thread { ProgressDialog dialog; File file; String path; DiskUsage diskUsage; FileSystemEntry entry; private static final int DELETION_SUCCESS = 0; private static final int DELETION_FAILED = 1; private static final int DELETION_CANCELED = 2; private static final int DELETION_IN_PROGRESS = 3; private volatile boolean cancelDeletion; private boolean backgroundDeletion; private int deletionStatus = DELETION_IN_PROGRESS; private int numDeletedDirectories = 0; private int numDeletedFiles = 0; private BackgroundDelete(final DiskUsage diskUsage, final FileSystemEntry entry) { this.diskUsage = diskUsage; this.entry = entry; path = entry.path2(); String deleteRoot = entry.absolutePath(); file = new File(deleteRoot); for (MountPoint mountPoint : MountPoint.getMountPoints(diskUsage).values()) { if ((mountPoint.root + "/").startsWith(deleteRoot + "/")) { Toast.makeText(diskUsage, "This delete operation will erase entire storage - canceled.", Toast.LENGTH_LONG).show(); return; } } if (!file.exists()) { Toast.makeText(diskUsage, format(R.string.path_doesnt_exist, path), Toast.LENGTH_LONG).show(); diskUsage.fileSystemState.removeInRenderThread(entry); return; } if (file.isFile()) { if (file.delete()) { Toast.makeText(diskUsage, str(R.string.file_deleted), Toast.LENGTH_SHORT).show(); diskUsage.fileSystemState.removeInRenderThread(entry); } else { Toast.makeText(diskUsage, str(R.string.error_file_wasnt_deleted), Toast.LENGTH_SHORT).show(); } return; } dialog = new ProgressDialog(diskUsage); dialog.setMessage(format(R.string.deleting_path, path)); dialog.setIndeterminate(true); dialog.setButton(diskUsage.getString(R.string.button_background), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { background(); dialog = null; } }); dialog.setButton2(diskUsage.getString(R.string.button_cancel), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { cancel(); dialog = null; } }); dialog.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss(DialogInterface x) { dialog = null; } }); dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface x) { dialog = null; } }); dialog.show(); start(); } private void uninstall(FileSystemPackage pkg) { String pkg_name = pkg.pkg; Uri packageURI = Uri.parse("package:" + pkg_name); Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI); diskUsage.startActivity(uninstallIntent); } static void startDelete(DiskUsage diskUsage, FileSystemEntry entry) { new BackgroundDelete(diskUsage, entry); } @Override public void run() { deletionStatus = deleteRecursively(file); // FIXME: use notification object when backgrounded diskUsage.handler.post(new Runnable() { public void run() { if (dialog != null) { try { dialog.dismiss(); } catch (Exception e) { // ignore exception } } diskUsage.fileSystemState.removeInRenderThread(entry); if (deletionStatus != DELETION_SUCCESS) { restore(); diskUsage.fileSystemState.requestRepaint(); diskUsage.fileSystemState.requestRepaintGPU(); } notifyUser(); } }); } public void restore() { Log.d("DiskUsage", "restore started for " + path); int displayBlockSize = diskUsage.fileSystemState.masterRoot.getDisplayBlockSize(); FileSystemEntry newEntry = new Scanner( // FIXME: hacked allocatedBlocks and heap size 20, displayBlockSize, null, 0, 4).scan( DataSource.get().createLegacyScanFile(diskUsage.getRootPath() + "/" + path)); // FIXME: may be problems in case of two deletions entry.parent.insert(newEntry, displayBlockSize); diskUsage.fileSystemState.restore(newEntry); Log.d("DiskUsage", "restoring undeleted: " + newEntry.name + " " + newEntry.sizeString()); } public void notifyUser() { Log.d("DiskUsage", "Delete: status = " + deletionStatus + " directories " + numDeletedDirectories + " files " + numDeletedFiles); if (deletionStatus == DELETION_SUCCESS) { Toast.makeText(diskUsage, format(R.string.deleted_n_directories_and_n_files, numDeletedDirectories, numDeletedFiles), Toast.LENGTH_LONG).show(); } else if (deletionStatus == DELETION_CANCELED) { Toast.makeText(diskUsage, format(R.string.deleted_n_directories_and_files_and_canceled, numDeletedDirectories, numDeletedFiles), Toast.LENGTH_LONG).show(); } else { Toast.makeText(diskUsage, format(R.string.deleted_n_directories_and_n_files_and_failed, numDeletedDirectories, numDeletedFiles), Toast.LENGTH_LONG).show(); } } public void background() { backgroundDeletion = true; } public void cancel() { cancelDeletion = true; } public final int deleteRecursively(File directory) { if (cancelDeletion) return DELETION_CANCELED; boolean isDirectory = directory.isDirectory(); if (isDirectory) { final File[] files = directory.listFiles(); if (files == null) return DELETION_FAILED; for (int i = 0; i < files.length; i++) { int status = deleteRecursively(files[i]); if (status != DELETION_SUCCESS) return status; } } boolean success = directory.delete(); if (success) { if (isDirectory) numDeletedDirectories++; else numDeletedFiles++; return DELETION_SUCCESS; } else { return DELETION_FAILED; } } private String format(int id, Object... args) { return diskUsage.getString(id, args); } private String str(int id) { return diskUsage.getString(id); } }