1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.sdkuilib.internal.tasks; 18 19 import com.android.sdklib.internal.repository.ITaskMonitor; 20 import com.android.util.Pair; 21 22 /** 23 * Internal class that implements the logic of an {@link ITaskMonitor}. 24 * It doesn't deal with any UI directly. Instead it delegates the UI to 25 * the provided {@link IProgressUiProvider}. 26 */ 27 class TaskMonitorImpl implements ITaskMonitor { 28 29 private static final double MAX_COUNT = 10000.0; 30 31 private interface ISubTaskMonitor extends ITaskMonitor { subIncProgress(double realDelta)32 public void subIncProgress(double realDelta); 33 } 34 35 private double mIncCoef = 0; 36 private double mValue = 0; 37 private final IProgressUiProvider mUi; 38 39 /** 40 * Returns true if the given {@code monitor} is an instance of {@link TaskMonitorImpl} 41 * or its private SubTaskMonitor. 42 */ isTaskMonitorImpl(ITaskMonitor monitor)43 public static boolean isTaskMonitorImpl(ITaskMonitor monitor) { 44 return monitor instanceof TaskMonitorImpl || monitor instanceof SubTaskMonitor; 45 } 46 47 /** 48 * Constructs a new {@link TaskMonitorImpl} that relies on the given 49 * {@link IProgressUiProvider} to change the user interface. 50 * @param ui The {@link IProgressUiProvider}. Cannot be null. 51 */ TaskMonitorImpl(IProgressUiProvider ui)52 public TaskMonitorImpl(IProgressUiProvider ui) { 53 mUi = ui; 54 } 55 56 /** Returns the {@link IProgressUiProvider} passed to the constructor. */ getUiProvider()57 public IProgressUiProvider getUiProvider() { 58 return mUi; 59 } 60 61 /** 62 * Sets the description in the current task dialog. 63 * This method can be invoked from a non-UI thread. 64 */ setDescription(String format, Object... args)65 public void setDescription(String format, Object... args) { 66 final String text = String.format(format, args); 67 mUi.setDescription(text); 68 } 69 70 /** 71 * Logs a "normal" information line. 72 * This method can be invoked from a non-UI thread. 73 */ log(String format, Object... args)74 public void log(String format, Object... args) { 75 String text = String.format(format, args); 76 mUi.log(text); 77 } 78 79 /** 80 * Logs an "error" information line. 81 * This method can be invoked from a non-UI thread. 82 */ logError(String format, Object... args)83 public void logError(String format, Object... args) { 84 String text = String.format(format, args); 85 mUi.logError(text); 86 } 87 88 /** 89 * Logs a "verbose" information line, that is extra details which are typically 90 * not that useful for the end-user and might be hidden until explicitly shown. 91 * This method can be invoked from a non-UI thread. 92 */ logVerbose(String format, Object... args)93 public void logVerbose(String format, Object... args) { 94 String text = String.format(format, args); 95 mUi.logVerbose(text); 96 } 97 98 /** 99 * Sets the max value of the progress bar. 100 * This method can be invoked from a non-UI thread. 101 * 102 * Weird things will happen if setProgressMax is called multiple times 103 * *after* {@link #incProgress(int)}: we don't try to adjust it on the 104 * fly. 105 */ setProgressMax(int max)106 public void setProgressMax(int max) { 107 assert max > 0; 108 // Always set the dialog's progress max to 10k since it only handles 109 // integers and we want to have a better inner granularity. Instead 110 // we use the max to compute a coefficient for inc deltas. 111 mUi.setProgressMax((int) MAX_COUNT); 112 mIncCoef = max > 0 ? MAX_COUNT / max : 0; 113 assert mIncCoef > 0; 114 } 115 getProgressMax()116 public int getProgressMax() { 117 return mIncCoef > 0 ? (int) (MAX_COUNT / mIncCoef) : 0; 118 } 119 120 /** 121 * Increments the current value of the progress bar. 122 * 123 * This method can be invoked from a non-UI thread. 124 */ incProgress(int delta)125 public void incProgress(int delta) { 126 if (delta > 0 && mIncCoef > 0) { 127 internalIncProgress(delta * mIncCoef); 128 } 129 } 130 internalIncProgress(double realDelta)131 private void internalIncProgress(double realDelta) { 132 mValue += realDelta; 133 mUi.setProgress((int)mValue); 134 } 135 136 /** 137 * Returns the current value of the progress bar, 138 * between 0 and up to {@link #setProgressMax(int)} - 1. 139 * 140 * This method can be invoked from a non-UI thread. 141 */ getProgress()142 public int getProgress() { 143 // mIncCoef is 0 if setProgressMax hasn't been used yet. 144 return mIncCoef > 0 ? (int)(mUi.getProgress() / mIncCoef) : 0; 145 } 146 147 /** 148 * Returns true if the "Cancel" button was selected. 149 * It is up to the task thread to pool this and exit. 150 */ isCancelRequested()151 public boolean isCancelRequested() { 152 return mUi.isCancelRequested(); 153 } 154 155 /** 156 * Displays a yes/no question dialog box. 157 * 158 * This implementation allow this to be called from any thread, it 159 * makes sure the dialog is opened synchronously in the ui thread. 160 * 161 * @param title The title of the dialog box 162 * @param message The error message 163 * @return true if YES was clicked. 164 */ displayPrompt(final String title, final String message)165 public boolean displayPrompt(final String title, final String message) { 166 return mUi.displayPrompt(title, message); 167 } 168 169 /** 170 * Displays a Login/Password dialog. This implementation allows this method to be 171 * called from any thread, it makes sure the dialog is opened synchronously 172 * in the ui thread. 173 * 174 * @param title The title of the dialog box 175 * @param message Message to be displayed 176 * @return Pair with entered login/password. Login is always the first 177 * element and Password is always the second. If any error occurs a 178 * pair with empty strings is returned. 179 */ displayLoginPasswordPrompt(String title, String message)180 public Pair<String, String> displayLoginPasswordPrompt(String title, String message) { 181 return mUi.displayLoginPasswordPrompt(title, message); 182 } 183 184 /** 185 * Creates a sub-monitor that will use up to tickCount on the progress bar. 186 * tickCount must be 1 or more. 187 */ createSubMonitor(int tickCount)188 public ITaskMonitor createSubMonitor(int tickCount) { 189 assert mIncCoef > 0; 190 assert tickCount > 0; 191 return new SubTaskMonitor(this, null, mValue, tickCount * mIncCoef); 192 } 193 194 // ----- ISdkLog interface ---- 195 error(Throwable throwable, String errorFormat, Object... arg)196 public void error(Throwable throwable, String errorFormat, Object... arg) { 197 if (errorFormat != null) { 198 logError("Error: " + errorFormat, arg); 199 } 200 201 if (throwable != null) { 202 logError("%s", throwable.getMessage()); //$NON-NLS-1$ 203 } 204 } 205 warning(String warningFormat, Object... arg)206 public void warning(String warningFormat, Object... arg) { 207 log("Warning: " + warningFormat, arg); 208 } 209 printf(String msgFormat, Object... arg)210 public void printf(String msgFormat, Object... arg) { 211 log(msgFormat, arg); 212 } 213 214 // ----- Sub Monitor ----- 215 216 private static class SubTaskMonitor implements ISubTaskMonitor { 217 218 private final TaskMonitorImpl mRoot; 219 private final ISubTaskMonitor mParent; 220 private final double mStart; 221 private final double mSpan; 222 private double mSubValue; 223 private double mSubCoef; 224 225 /** 226 * Creates a new sub task monitor which will work for the given range [start, start+span] 227 * in its parent. 228 * 229 * @param taskMonitor The ProgressTask root 230 * @param parent The immediate parent. Can be the null or another sub task monitor. 231 * @param start The start value in the root's coordinates 232 * @param span The span value in the root's coordinates 233 */ SubTaskMonitor(TaskMonitorImpl taskMonitor, ISubTaskMonitor parent, double start, double span)234 public SubTaskMonitor(TaskMonitorImpl taskMonitor, 235 ISubTaskMonitor parent, 236 double start, 237 double span) { 238 mRoot = taskMonitor; 239 mParent = parent; 240 mStart = start; 241 mSpan = span; 242 mSubValue = start; 243 } 244 isCancelRequested()245 public boolean isCancelRequested() { 246 return mRoot.isCancelRequested(); 247 } 248 setDescription(String format, Object... args)249 public void setDescription(String format, Object... args) { 250 mRoot.setDescription(format, args); 251 } 252 log(String format, Object... args)253 public void log(String format, Object... args) { 254 mRoot.log(format, args); 255 } 256 logError(String format, Object... args)257 public void logError(String format, Object... args) { 258 mRoot.logError(format, args); 259 } 260 logVerbose(String format, Object... args)261 public void logVerbose(String format, Object... args) { 262 mRoot.logVerbose(format, args); 263 } 264 setProgressMax(int max)265 public void setProgressMax(int max) { 266 assert max > 0; 267 mSubCoef = max > 0 ? mSpan / max : 0; 268 assert mSubCoef > 0; 269 } 270 getProgressMax()271 public int getProgressMax() { 272 return mSubCoef > 0 ? (int) (mSpan / mSubCoef) : 0; 273 } 274 getProgress()275 public int getProgress() { 276 // subCoef can be 0 if setProgressMax() and incProgress() haven't been called yet 277 assert mSubValue == mStart || mSubCoef > 0; 278 return mSubCoef > 0 ? (int)((mSubValue - mStart) / mSubCoef) : 0; 279 } 280 incProgress(int delta)281 public void incProgress(int delta) { 282 if (delta > 0 && mSubCoef > 0) { 283 subIncProgress(delta * mSubCoef); 284 } 285 } 286 subIncProgress(double realDelta)287 public void subIncProgress(double realDelta) { 288 mSubValue += realDelta; 289 if (mParent != null) { 290 mParent.subIncProgress(realDelta); 291 } else { 292 mRoot.internalIncProgress(realDelta); 293 } 294 } 295 displayPrompt(String title, String message)296 public boolean displayPrompt(String title, String message) { 297 return mRoot.displayPrompt(title, message); 298 } 299 displayLoginPasswordPrompt(String title, String message)300 public Pair<String, String> displayLoginPasswordPrompt(String title, String message) { 301 return mRoot.displayLoginPasswordPrompt(title, message); 302 } 303 createSubMonitor(int tickCount)304 public ITaskMonitor createSubMonitor(int tickCount) { 305 assert mSubCoef > 0; 306 assert tickCount > 0; 307 return new SubTaskMonitor(mRoot, 308 this, 309 mSubValue, 310 tickCount * mSubCoef); 311 } 312 313 // ----- ISdkLog interface ---- 314 error(Throwable throwable, String errorFormat, Object... arg)315 public void error(Throwable throwable, String errorFormat, Object... arg) { 316 mRoot.error(throwable, errorFormat, arg); 317 } 318 warning(String warningFormat, Object... arg)319 public void warning(String warningFormat, Object... arg) { 320 mRoot.warning(warningFormat, arg); 321 } 322 printf(String msgFormat, Object... arg)323 public void printf(String msgFormat, Object... arg) { 324 mRoot.printf(msgFormat, arg); 325 } 326 } 327 } 328