diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/internal/repository/SettingsPage.java b/tools/sdkmanager/app/src/com/android/sdkmanager/internal/repository/SettingsPage.java index 77e6a54fe..b07617f9e 100755 --- a/tools/sdkmanager/app/src/com/android/sdkmanager/internal/repository/SettingsPage.java +++ b/tools/sdkmanager/app/src/com/android/sdkmanager/internal/repository/SettingsPage.java @@ -21,6 +21,8 @@ import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.sdkuilib.internal.repository.ISettingsPage; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; @@ -28,16 +30,11 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.FileWriter; import java.io.IOException; -import java.io.InputStream; import java.net.URL; import java.util.Properties; diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java index c8f7c06a6..85596ba7c 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java @@ -45,18 +45,27 @@ public interface ITaskMonitor { /** * Sets the max value of the progress bar. * This method can be invoked from a non-UI thread. + * + * This method MUST be invoked once before using {@link #incProgress(int)} or + * {@link #getProgress()} or {@link #createSubMonitor(int)}. Callers are + * discouraged from using more than once -- implementations can either discard + * the next calls or behave incoherently. */ public void setProgressMax(int max); /** * Increments the current value of the progress bar. * This method can be invoked from a non-UI thread. + * + * Callers MUST use setProgressMax before using this method. */ public void incProgress(int delta); /** * Returns the current value of the progress bar, * between 0 and up to {@link #setProgressMax(int)} - 1. + * + * Callers MUST use setProgressMax before using this method. */ public int getProgress(); @@ -66,4 +75,10 @@ public interface ITaskMonitor { * as possible. */ public boolean isCancelRequested(); + + /** + * Creates a sub-monitor that will use up to tickCount on the progress bar. + * tickCount must be 1 or more. + */ + public ITaskMonitor createSubMonitor(int tickCount); } diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java index d8ab806ea..c58a21412 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java @@ -68,7 +68,7 @@ public class RepoSource implements IDescription { } /** - * Returns the list of known packages found by the last call to {@link #load(ITaskFactory)}. + * Returns the list of known packages found by the last call to {@link #load(ITaskMonitor)}. * This is null when the source hasn't been loaded yet. */ public Package[] getPackages() { @@ -77,7 +77,7 @@ public class RepoSource implements IDescription { /** * Clear the internal packages list. After this call, {@link #getPackages()} will return - * null till {@link #load(ITaskFactory)} is called. + * null till {@link #load(ITaskMonitor)} is called. */ public void clearPackages() { mPackages = null; @@ -94,47 +94,43 @@ public class RepoSource implements IDescription { /** * Tries to fetch the repository index for the given URL. */ - public void load(ITaskFactory taskFactory) { + public void load(ITaskMonitor monitor) { - taskFactory.start("Init SDK Updater", new ITask() { - public void run(ITaskMonitor monitor) { - monitor.setProgressMax(4); + monitor.setProgressMax(4); - setDefaultDescription(); + setDefaultDescription(); - monitor.setDescription("Fetching %1$s", mUrl); - monitor.incProgress(1); + monitor.setDescription("Fetching %1$s", mUrl); + monitor.incProgress(1); - String xml = fetchUrl(mUrl, monitor); + String xml = fetchUrl(mUrl, monitor); - if (xml == null) { - mDescription += String.format("\nFailed to fetch URL %1$s", mUrl); - return; - } + if (xml == null) { + mDescription += String.format("\nFailed to fetch URL %1$s", mUrl); + return; + } - monitor.setDescription("Validate XML"); - monitor.incProgress(1); + monitor.setDescription("Validate XML"); + monitor.incProgress(1); - if (!validateXml(xml, monitor)) { - mDescription += String.format("\nFailed to validate XML at %1$s", mUrl); - return; - } + if (!validateXml(xml, monitor)) { + mDescription += String.format("\nFailed to validate XML at %1$s", mUrl); + return; + } - monitor.setDescription("Parse XML"); - monitor.incProgress(1); - parsePackages(xml, monitor); - if (mPackages.length == 0) { - mDescription += "\nNo packages found."; - } else if (mPackages.length == 1) { - mDescription += "\nOne package found."; - } else { - mDescription += String.format("\n%1$d packages found.", mPackages.length); - } + monitor.setDescription("Parse XML"); + monitor.incProgress(1); + parsePackages(xml, monitor); + if (mPackages.length == 0) { + mDescription += "\nNo packages found."; + } else if (mPackages.length == 1) { + mDescription += "\nOne package found."; + } else { + mDescription += String.format("\n%1$d packages found.", mPackages.length); + } - // done - monitor.incProgress(1); - } - }); + // done + monitor.incProgress(1); } private void setDefaultDescription() { diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressDialog.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressDialog.java index a5cb86fb3..ca847c3c1 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressDialog.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressDialog.java @@ -320,15 +320,15 @@ final class ProgressDialog extends Dialog { } /** - * Increments the current value of the progress bar. + * Sets the current value of the progress bar. * This method can be invoked from a non-UI thread. */ - public void incProgress(final int delta) { + public void setProgress(final int value) { if (!mDialogShell.isDisposed()) { mDialogShell.getDisplay().syncExec(new Runnable() { public void run() { if (!mProgressBar.isDisposed()) { - mProgressBar.setSelection(mProgressBar.getSelection() + delta); + mProgressBar.setSelection(value); } } }); diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressTask.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressTask.java index 709cce04c..1ec728701 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressTask.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressTask.java @@ -28,8 +28,12 @@ import org.eclipse.swt.widgets.Shell; */ class ProgressTask implements ITaskMonitor { - private ProgressDialog mDialog; + private static final double MAX_COUNT = 10000.0; + + private final ProgressDialog mDialog; private boolean mAutomaticallyCloseOnTaskCompletion = true; + private double mIncCoef = 0; + private double mValue = 0; /** @@ -46,29 +50,39 @@ class ProgressTask implements ITaskMonitor { /** * Sets the description in the current task dialog. - * This method can be invoke from a non-UI thread. + * This method can be invoked from a non-UI thread. */ - public void setDescription(final String descriptionFormat, final Object...args) { + public void setDescription(String descriptionFormat, Object...args) { mDialog.setDescription(descriptionFormat, args); } /** * Sets the description in the current task dialog. - * This method can be invoke from a non-UI thread. + * This method can be invoked from a non-UI thread. */ - public void setResult(final String resultFormat, final Object...args) { + public void setResult(String resultFormat, Object...args) { mAutomaticallyCloseOnTaskCompletion = false; mDialog.setResult(resultFormat, args); } /** * Sets the max value of the progress bar. - * This method can be invoke from a non-UI thread. + * This method can be invoked from a non-UI thread. + * + * Weird things will happen if setProgressMax is called multiple times + * *after* {@link #incProgress(int)}: we don't try to adjust it on the + * fly. * * @see ProgressBar#setMaximum(int) */ - public void setProgressMax(final int max) { - mDialog.setProgressMax(max); + public void setProgressMax(int max) { + assert max > 0; + // Always set the dialog's progress max to 10k since it only handles + // integers and we want to have a better inner granularity. Instead + // we use the max to compute a coefficient for inc deltas. + mDialog.setProgressMax((int) MAX_COUNT); + mIncCoef = max > 0 ? MAX_COUNT / max : 0; + assert mIncCoef > 0; } /** @@ -76,8 +90,15 @@ class ProgressTask implements ITaskMonitor { * * This method can be invoked from a non-UI thread. */ - public void incProgress(final int delta) { - mDialog.incProgress(delta); + public void incProgress(int delta) { + assert mIncCoef > 0; + assert delta > 0; + internalIncProgress(delta * mIncCoef); + } + + private void internalIncProgress(double realDelta) { + mValue += realDelta; + mDialog.setProgress((int)mValue); } /** @@ -87,7 +108,8 @@ class ProgressTask implements ITaskMonitor { * This method can be invoked from a non-UI thread. */ public int getProgress() { - return mDialog.getProgress(); + assert mIncCoef > 0; + return mIncCoef > 0 ? (int)(mDialog.getProgress() / mIncCoef) : 0; } /** @@ -119,4 +141,95 @@ class ProgressTask implements ITaskMonitor { } return null; } + + /** + * Creates a sub-monitor that will use up to tickCount on the progress bar. + * tickCount must be 1 or more. + */ + public ITaskMonitor createSubMonitor(int tickCount) { + assert mIncCoef > 0; + assert tickCount > 0; + return new SubTaskMonitor(this, null, mValue, tickCount * mIncCoef); + } + + private interface ISubTaskMonitor extends ITaskMonitor { + public void subIncProgress(double realDelta); + } + + private static class SubTaskMonitor implements ISubTaskMonitor { + + private final ProgressTask mRoot; + private final ISubTaskMonitor mParent; + private final double mStart; + private final double mSpan; + private double mSubValue; + private double mSubCoef; + + /** + * Creates a new sub task monitor which will work for the given range [start, start+span] + * in its parent. + * + * @param root The ProgressTask root + * @param parent The immediate parent. Can be the null or another sub task monitor. + * @param start The start value in the root's coordinates + * @param span The span value in the root's coordinates + */ + public SubTaskMonitor(ProgressTask root, + ISubTaskMonitor parent, + double start, + double span) { + mRoot = root; + mParent = parent; + mStart = start; + mSpan = span; + mSubValue = start; + } + + public boolean isCancelRequested() { + return mRoot.isCancelRequested(); + } + + public void setDescription(String descriptionFormat, Object... args) { + mRoot.setDescription(descriptionFormat, args); + } + + public void setResult(String resultFormat, Object... args) { + mRoot.setResult(resultFormat, args); + } + + public void setProgressMax(int max) { + assert max > 0; + mSubCoef = max > 0 ? mSpan / max : 0; + assert mSubCoef > 0; + } + + public int getProgress() { + assert mSubCoef > 0; + return mSubCoef > 0 ? (int)((mSubValue - mStart) / mSubCoef) : 0; + } + + public void incProgress(int delta) { + assert mSubCoef > 0; + subIncProgress(delta * mSubCoef); + } + + public void subIncProgress(double realDelta) { + mSubValue += realDelta; + if (mParent != null) { + mParent.subIncProgress(realDelta); + } else { + mRoot.internalIncProgress(realDelta); + } + } + + public ITaskMonitor createSubMonitor(int tickCount) { + assert mSubCoef > 0; + assert tickCount > 0; + return new SubTaskMonitor(mRoot, + this, + mSubValue, + tickCount * mSubCoef); + } + } + } diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java index 6cc11a349..fb0c504a6 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java @@ -19,6 +19,8 @@ package com.android.sdkuilib.internal.repository; import com.android.sdklib.internal.repository.Archive; import com.android.sdklib.internal.repository.IDescription; +import com.android.sdklib.internal.repository.ITask; +import com.android.sdklib.internal.repository.ITaskMonitor; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.CheckboxTreeViewer; @@ -265,7 +267,7 @@ public class RemotePackagesPage extends Composite { private void onRefreshSelected() { if (mUpdaterWindow != null) { - mUpdaterWindow.refreshSources(false /*forceFetching*/); + mUpdaterWindow.refreshSources(false /*forceFetching*/, null /*monitor*/); } } diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java index 3f020d112..a17077507 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java @@ -18,6 +18,8 @@ package com.android.sdkuilib.internal.repository; import com.android.sdklib.internal.repository.Archive; import com.android.sdklib.internal.repository.IDescription; +import com.android.sdklib.internal.repository.ITask; +import com.android.sdklib.internal.repository.ITaskMonitor; import com.android.sdklib.internal.repository.Package; import com.android.sdklib.internal.repository.RepoSource; import com.android.sdklib.internal.repository.RepoSources; @@ -110,11 +112,17 @@ class RepoSourcesAdapter { return ((RepoSourcesAdapter) parentElement).mRepoSources.getSources().toArray(); } else if (parentElement instanceof RepoSource) { - RepoSource source = (RepoSource) parentElement; + final RepoSource source = (RepoSource) parentElement; Package[] packages = source.getPackages(); if (packages == null) { - source.load(mInput.mRepoSources.getTaskFactory()); + + mInput.mRepoSources.getTaskFactory().start("Loading Source", new ITask() { + public void run(ITaskMonitor monitor) { + source.load(monitor); + } + }); + packages = source.getPackages(); } if (packages != null) { diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java index cf679c79f..3e98faecd 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java @@ -407,17 +407,14 @@ public class UpdaterWindowImpl { } public void updateAll() { - refreshSources(true); + mTaskFactory.start("Update Archives", new ITask() { + public void run(ITaskMonitor monitor) { + monitor.setProgressMax(3); - // TODO have refreshSources reuse the current progress task -// mTaskFactory.start("Update Archives", new ITask() { -// public void run(ITaskMonitor monitor) { -// monitor.setProgressMax(3); -// -// monitor.setDescription("Refresh sources"); -// refreshSources(true); -// } -// }); + monitor.setDescription("Refresh sources"); + refreshSources(true, monitor.createSubMonitor(1)); + } + }); } /** @@ -426,32 +423,26 @@ public class UpdaterWindowImpl { * @param forceFetching When true, load sources that haven't been loaded yet. When * false, only refresh sources that have been loaded yet. */ - public void refreshSources(final boolean forceFetching) { - ArrayList sources = mUpdaterData.getSources().getSources(); - for (RepoSource source : sources) { - if (forceFetching || source.getPackages() != null) { - source.load(mTaskFactory); + public void refreshSources(final boolean forceFetching, ITaskMonitor monitor) { + ITask task = new ITask() { + public void run(ITaskMonitor monitor) { + ArrayList sources = mUpdaterData.getSources().getSources(); + monitor.setProgressMax(sources.size()); + for (RepoSource source : sources) { + if (forceFetching || source.getPackages() != null) { + source.load(monitor.createSubMonitor(1)); + } + monitor.incProgress(1); + + } } + }; + if (monitor != null) { + task.run(monitor); + } else { + mTaskFactory.start("Refresh Sources", task); } - - // TODO have source.load reuse the current progress task -// mTaskFactory.start("Refresh sources", new ITask() { -// public void run(ITaskMonitor monitor) { -// ArrayList sources = mUpdaterData.getSources().getSources(); -// monitor.setProgressMax(sources.size()); -// -// for (RepoSource source : sources) { -// if (forceFetching || source.getPackages() != null) { -// monitor.setDescription(String.format("Refresh %1$s", -// source.getShortDescription())); -// source.load(mTaskFactory); -// } -// monitor.incProgress(1); -// } -// } -// }); - } // End of hiding from SWT Designer