/** * DiskUsage - displays sdcard usage on android. * Copyright (C) 2008-2011 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.text.NumberFormat; import java.util.ArrayList; import android.app.AlertDialog; import android.content.Context; import android.graphics.Paint; import android.os.Bundle; import android.text.Spannable; import android.text.SpannableString; import android.text.style.StyleSpan; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.ProgressBar; import android.widget.TextView; import com.google.android.diskusage.entity.FileSystemEntry; public class MyProgressDialog extends AlertDialog { private final Context context; private TextView percentView; private TextView detailsView; private ProgressBar progressBar; private CharSequence details; private long progress; private long max; private NumberFormat progressPercentFormat; public MyProgressDialog(Context context) { super(context); this.context = context; } public void setMax(long max) { this.max = max; } private int depth = 0; private boolean warned = false; private final String path(FileSystemEntry entry) { ArrayList<String> pathElements = new ArrayList<String>(); FileSystemEntry current = entry; while (current != null) { pathElements.add(current.name); current = current.parent; } depth = pathElements.size(); if (pathElements.size() < 2) return ""; pathElements.remove(pathElements.size() - 1); StringBuilder path = new StringBuilder(); String sep = ""; for (int i = pathElements.size() - 1; i >= 0; i--) { path.append(sep); path.append(pathElements.get(i)); sep = "/"; } return path.toString(); } char[] prevPathChars = new char[0]; private String makePathString(String path) { // Log.d("diskusage", "path = " + path); char[] pathChars = path.toCharArray(); char[] prevPathChars = this.prevPathChars; int len = Math.min(pathChars.length, prevPathChars.length); int diff; TextView detailsView = this.detailsView; Paint textPaint = detailsView.getPaint(); for (diff = 0; diff < len; diff++) { if (pathChars[diff] == prevPathChars[diff]) continue; break; } float winWidth = detailsView.getWidth(); float extraTextWidth = textPaint.measureText("/.../G"); float width = winWidth - extraTextWidth; if (width < extraTextWidth) return path; int firstSep = -2; int lastSep = -2; try { if (textPaint.measureText(path, 0, diff) < width) { this.prevPathChars = pathChars; return path; } lastSep = path.lastIndexOf('/', diff); firstSep = path.indexOf("/"); if (lastSep == -1 || firstSep == -1) return path; float firstPart = textPaint.measureText(path, 0, firstSep); float lastPart = textPaint.measureText(path, lastSep, diff); if (firstPart + lastPart > width) { // need to break first and last string do { if (firstPart > lastPart * 3) { firstSep /= 2; firstPart = textPaint.measureText(path, 0, firstSep); } else { lastSep = (lastSep + diff) / 2; lastPart = textPaint.measureText(path, lastSep, diff); } } while (firstPart + lastPart > width); this.prevPathChars = pathChars; return path.substring(0, firstSep) + "..." + path.substring(lastSep); } while (true) { boolean success = false; int newLastSep = path.lastIndexOf('/', lastSep - 1); if (newLastSep != -1 && newLastSep >= firstSep) { float newLastPart = textPaint.measureText(path, newLastSep, diff); if (firstPart + newLastPart < width) { success = true; lastPart = newLastPart; lastSep = newLastSep; } } int newFirstSep = path.indexOf('/', firstSep + 1); if (newFirstSep != -1 && newFirstSep <= lastSep) { float newFirstPart = textPaint.measureText(path, 0, newFirstSep); if (newFirstPart + lastPart < width) { success = true; firstPart = newFirstPart; firstSep = newFirstSep; } } if (!success) { this.prevPathChars = pathChars; if (firstSep >= lastSep) { return path; } return path.substring(0, firstSep) + "/.../" + path.substring(lastSep + 1); } } } catch (RuntimeException e) { throw new RuntimeException( "path = " + path + "[" + firstSep + ":" + lastSep + "]" + " win =" + winWidth + " extra=" + extraTextWidth + " diff=" + diff, e); } } public void onProgressChanged() { /* Update the number and percent */ long progress = MyProgressDialog.this.progress; long max = MyProgressDialog.this.max; double percent = (double) progress / (double) max * basePercent + (1 - basePercent); progressBar.setProgress((int)(percent * 10000)); detailsView.setText(details); // progressNumber.setText(String.format(format, progress, max)); SpannableString tmp = new SpannableString(progressPercentFormat.format(percent)); tmp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, tmp.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); percentView.setText(tmp); // Log.d("diskusage", "details: " + details); // Log.d("diskusage", "depth = " + depth); if (depth > 40 && !warned) { warned = true; setMessage("Cyclic dirs? Broken filesystem?"); } } public void setProgress(long progress, FileSystemEntry entry) { this.progress = progress; this.details = makePathString(path(entry)); // Log.d("diskusage", "makePath = " + this.details); onProgressChanged(); } double basePercent = 1; public void switchToSecondary() { basePercent = 1 - (double) progress / (double) max; } public void setProgress(long progress, CharSequence details) { this.progress = progress; this.details = details; onProgressChanged(); } @Override protected void onCreate(Bundle savedInstanceState) { LayoutInflater inflater = LayoutInflater.from(context); View view = inflater.inflate(R.layout.progress, null); progressBar = (ProgressBar) view.findViewById(R.id.progress); progressBar.setMax(10000); detailsView = (TextView) view.findViewById(R.id.progress_details); percentView = (TextView) view.findViewById(R.id.progress_percent); progressPercentFormat = NumberFormat.getPercentInstance(); progressPercentFormat.setMaximumFractionDigits(0); setView(view); progressBar.setMax(10000); onProgressChanged(); super.onCreate(savedInstanceState); } }