/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.sdkuilib.internal.tasks; import com.android.annotations.NonNull; import com.android.sdklib.internal.repository.ITaskMonitor; import com.android.sdklib.internal.repository.UserCredentials; /** * Internal class that implements the logic of an {@link ITaskMonitor}. * It doesn't deal with any UI directly. Instead it delegates the UI to * the provided {@link IProgressUiProvider}. */ class TaskMonitorImpl implements ITaskMonitor { private static final double MAX_COUNT = 10000.0; private interface ISubTaskMonitor extends ITaskMonitor { public void subIncProgress(double realDelta); } private double mIncCoef = 0; private double mValue = 0; private final IProgressUiProvider mUi; /** * Returns true if the given {@code monitor} is an instance of {@link TaskMonitorImpl} * or its private SubTaskMonitor. */ public static boolean isTaskMonitorImpl(ITaskMonitor monitor) { return monitor instanceof TaskMonitorImpl || monitor instanceof SubTaskMonitor; } /** * Constructs a new {@link TaskMonitorImpl} that relies on the given * {@link IProgressUiProvider} to change the user interface. * @param ui The {@link IProgressUiProvider}. Cannot be null. */ public TaskMonitorImpl(IProgressUiProvider ui) { mUi = ui; } /** Returns the {@link IProgressUiProvider} passed to the constructor. */ public IProgressUiProvider getUiProvider() { return mUi; } /** * Sets the description in the current task dialog. * This method can be invoked from a non-UI thread. */ @Override public void setDescription(String format, Object... args) { final String text = String.format(format, args); mUi.setDescription(text); } /** * Logs a "normal" information line. * This method can be invoked from a non-UI thread. */ @Override public void log(String format, Object... args) { String text = String.format(format, args); mUi.log(text); } /** * Logs an "error" information line. * This method can be invoked from a non-UI thread. */ @Override public void logError(String format, Object... args) { String text = String.format(format, args); mUi.logError(text); } /** * Logs a "verbose" information line, that is extra details which are typically * not that useful for the end-user and might be hidden until explicitly shown. * This method can be invoked from a non-UI thread. */ @Override public void logVerbose(String format, Object... args) { String text = String.format(format, args); mUi.logVerbose(text); } /** * Sets the max value of the progress bar. * 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. */ @Override 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. mUi.setProgressMax((int) MAX_COUNT); mIncCoef = max > 0 ? MAX_COUNT / max : 0; assert mIncCoef > 0; } @Override public int getProgressMax() { return mIncCoef > 0 ? (int) (MAX_COUNT / mIncCoef) : 0; } /** * Increments the current value of the progress bar. * * This method can be invoked from a non-UI thread. */ @Override public void incProgress(int delta) { if (delta > 0 && mIncCoef > 0) { internalIncProgress(delta * mIncCoef); } } private void internalIncProgress(double realDelta) { mValue += realDelta; mUi.setProgress((int)mValue); } /** * Returns the current value of the progress bar, * between 0 and up to {@link #setProgressMax(int)} - 1. * * This method can be invoked from a non-UI thread. */ @Override public int getProgress() { // mIncCoef is 0 if setProgressMax hasn't been used yet. return mIncCoef > 0 ? (int)(mUi.getProgress() / mIncCoef) : 0; } /** * Returns true if the "Cancel" button was selected. * It is up to the task thread to pool this and exit. */ @Override public boolean isCancelRequested() { return mUi.isCancelRequested(); } /** * Displays a yes/no question dialog box. * * This implementation allow this to be called from any thread, it * makes sure the dialog is opened synchronously in the ui thread. * * @param title The title of the dialog box * @param message The error message * @return true if YES was clicked. */ @Override public boolean displayPrompt(final String title, final String message) { return mUi.displayPrompt(title, message); } /** * Displays a Login/Password dialog. This implementation allows this method to be * called from any thread, it makes sure the dialog is opened synchronously * in the ui thread. * * @param title The title of the dialog box * @param message Message to be displayed * @return Pair with entered login/password. Login is always the first * element and Password is always the second. If any error occurs a * pair with empty strings is returned. */ @Override public UserCredentials displayLoginCredentialsPrompt(String title, String message) { return mUi.displayLoginCredentialsPrompt(title, message); } /** * Creates a sub-monitor that will use up to tickCount on the progress bar. * tickCount must be 1 or more. */ @Override public ITaskMonitor createSubMonitor(int tickCount) { assert mIncCoef > 0; assert tickCount > 0; return new SubTaskMonitor(this, null, mValue, tickCount * mIncCoef); } // ----- ILogger interface ---- @Override public void error(Throwable throwable, String errorFormat, Object... arg) { if (errorFormat != null) { logError("Error: " + errorFormat, arg); } if (throwable != null) { logError("%s", throwable.getMessage()); //$NON-NLS-1$ } } @Override public void warning(@NonNull String warningFormat, Object... arg) { log("Warning: " + warningFormat, arg); } @Override public void info(@NonNull String msgFormat, Object... arg) { log(msgFormat, arg); } @Override public void verbose(@NonNull String msgFormat, Object... arg) { log(msgFormat, arg); } // ----- Sub Monitor ----- private static class SubTaskMonitor implements ISubTaskMonitor { private final TaskMonitorImpl 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 taskMonitor 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(TaskMonitorImpl taskMonitor, ISubTaskMonitor parent, double start, double span) { mRoot = taskMonitor; mParent = parent; mStart = start; mSpan = span; mSubValue = start; } @Override public boolean isCancelRequested() { return mRoot.isCancelRequested(); } @Override public void setDescription(String format, Object... args) { mRoot.setDescription(format, args); } @Override public void log(String format, Object... args) { mRoot.log(format, args); } @Override public void logError(String format, Object... args) { mRoot.logError(format, args); } @Override public void logVerbose(String format, Object... args) { mRoot.logVerbose(format, args); } @Override public void setProgressMax(int max) { assert max > 0; mSubCoef = max > 0 ? mSpan / max : 0; assert mSubCoef > 0; } @Override public int getProgressMax() { return mSubCoef > 0 ? (int) (mSpan / mSubCoef) : 0; } @Override public int getProgress() { // subCoef can be 0 if setProgressMax() and incProgress() haven't been called yet assert mSubValue == mStart || mSubCoef > 0; return mSubCoef > 0 ? (int)((mSubValue - mStart) / mSubCoef) : 0; } @Override public void incProgress(int delta) { if (delta > 0 && mSubCoef > 0) { subIncProgress(delta * mSubCoef); } } @Override public void subIncProgress(double realDelta) { mSubValue += realDelta; if (mParent != null) { mParent.subIncProgress(realDelta); } else { mRoot.internalIncProgress(realDelta); } } @Override public boolean displayPrompt(String title, String message) { return mRoot.displayPrompt(title, message); } @Override public UserCredentials displayLoginCredentialsPrompt(String title, String message) { return mRoot.displayLoginCredentialsPrompt(title, message); } @Override public ITaskMonitor createSubMonitor(int tickCount) { assert mSubCoef > 0; assert tickCount > 0; return new SubTaskMonitor(mRoot, this, mSubValue, tickCount * mSubCoef); } // ----- ILogger interface ---- @Override public void error(Throwable throwable, String errorFormat, Object... arg) { mRoot.error(throwable, errorFormat, arg); } @Override public void warning(@NonNull String warningFormat, Object... arg) { mRoot.warning(warningFormat, arg); } @Override public void info(@NonNull String msgFormat, Object... arg) { mRoot.info(msgFormat, arg); } @Override public void verbose(@NonNull String msgFormat, Object... arg) { mRoot.verbose(msgFormat, arg); } } }