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.sdklib.internal.repository.UserCredentials; 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 */ 65 @Override setDescription(String format, Object... args)66 public void setDescription(String format, Object... args) { 67 final String text = String.format(format, args); 68 mUi.setDescription(text); 69 } 70 71 /** 72 * Logs a "normal" information line. 73 * This method can be invoked from a non-UI thread. 74 */ 75 @Override log(String format, Object... args)76 public void log(String format, Object... args) { 77 String text = String.format(format, args); 78 mUi.log(text); 79 } 80 81 /** 82 * Logs an "error" information line. 83 * This method can be invoked from a non-UI thread. 84 */ 85 @Override logError(String format, Object... args)86 public void logError(String format, Object... args) { 87 String text = String.format(format, args); 88 mUi.logError(text); 89 } 90 91 /** 92 * Logs a "verbose" information line, that is extra details which are typically 93 * not that useful for the end-user and might be hidden until explicitly shown. 94 * This method can be invoked from a non-UI thread. 95 */ 96 @Override logVerbose(String format, Object... args)97 public void logVerbose(String format, Object... args) { 98 String text = String.format(format, args); 99 mUi.logVerbose(text); 100 } 101 102 /** 103 * Sets the max value of the progress bar. 104 * This method can be invoked from a non-UI thread. 105 * 106 * Weird things will happen if setProgressMax is called multiple times 107 * *after* {@link #incProgress(int)}: we don't try to adjust it on the 108 * fly. 109 */ 110 @Override setProgressMax(int max)111 public void setProgressMax(int max) { 112 assert max > 0; 113 // Always set the dialog's progress max to 10k since it only handles 114 // integers and we want to have a better inner granularity. Instead 115 // we use the max to compute a coefficient for inc deltas. 116 mUi.setProgressMax((int) MAX_COUNT); 117 mIncCoef = max > 0 ? MAX_COUNT / max : 0; 118 assert mIncCoef > 0; 119 } 120 121 @Override getProgressMax()122 public int getProgressMax() { 123 return mIncCoef > 0 ? (int) (MAX_COUNT / mIncCoef) : 0; 124 } 125 126 /** 127 * Increments the current value of the progress bar. 128 * 129 * This method can be invoked from a non-UI thread. 130 */ 131 @Override incProgress(int delta)132 public void incProgress(int delta) { 133 if (delta > 0 && mIncCoef > 0) { 134 internalIncProgress(delta * mIncCoef); 135 } 136 } 137 internalIncProgress(double realDelta)138 private void internalIncProgress(double realDelta) { 139 mValue += realDelta; 140 mUi.setProgress((int)mValue); 141 } 142 143 /** 144 * Returns the current value of the progress bar, 145 * between 0 and up to {@link #setProgressMax(int)} - 1. 146 * 147 * This method can be invoked from a non-UI thread. 148 */ 149 @Override getProgress()150 public int getProgress() { 151 // mIncCoef is 0 if setProgressMax hasn't been used yet. 152 return mIncCoef > 0 ? (int)(mUi.getProgress() / mIncCoef) : 0; 153 } 154 155 /** 156 * Returns true if the "Cancel" button was selected. 157 * It is up to the task thread to pool this and exit. 158 */ 159 @Override isCancelRequested()160 public boolean isCancelRequested() { 161 return mUi.isCancelRequested(); 162 } 163 164 /** 165 * Displays a yes/no question dialog box. 166 * 167 * This implementation allow this to be called from any thread, it 168 * makes sure the dialog is opened synchronously in the ui thread. 169 * 170 * @param title The title of the dialog box 171 * @param message The error message 172 * @return true if YES was clicked. 173 */ 174 @Override displayPrompt(final String title, final String message)175 public boolean displayPrompt(final String title, final String message) { 176 return mUi.displayPrompt(title, message); 177 } 178 179 /** 180 * Displays a Login/Password dialog. This implementation allows this method to be 181 * called from any thread, it makes sure the dialog is opened synchronously 182 * in the ui thread. 183 * 184 * @param title The title of the dialog box 185 * @param message Message to be displayed 186 * @return Pair with entered login/password. Login is always the first 187 * element and Password is always the second. If any error occurs a 188 * pair with empty strings is returned. 189 */ 190 @Override displayLoginCredentialsPrompt(String title, String message)191 public UserCredentials displayLoginCredentialsPrompt(String title, String message) { 192 return mUi.displayLoginCredentialsPrompt(title, message); 193 } 194 195 /** 196 * Creates a sub-monitor that will use up to tickCount on the progress bar. 197 * tickCount must be 1 or more. 198 */ 199 @Override createSubMonitor(int tickCount)200 public ITaskMonitor createSubMonitor(int tickCount) { 201 assert mIncCoef > 0; 202 assert tickCount > 0; 203 return new SubTaskMonitor(this, null, mValue, tickCount * mIncCoef); 204 } 205 206 // ----- ISdkLog interface ---- 207 208 @Override error(Throwable throwable, String errorFormat, Object... arg)209 public void error(Throwable throwable, String errorFormat, Object... arg) { 210 if (errorFormat != null) { 211 logError("Error: " + errorFormat, arg); 212 } 213 214 if (throwable != null) { 215 logError("%s", throwable.getMessage()); //$NON-NLS-1$ 216 } 217 } 218 219 @Override warning(String warningFormat, Object... arg)220 public void warning(String warningFormat, Object... arg) { 221 log("Warning: " + warningFormat, arg); 222 } 223 224 @Override printf(String msgFormat, Object... arg)225 public void printf(String msgFormat, Object... arg) { 226 log(msgFormat, arg); 227 } 228 229 // ----- Sub Monitor ----- 230 231 private static class SubTaskMonitor implements ISubTaskMonitor { 232 233 private final TaskMonitorImpl mRoot; 234 private final ISubTaskMonitor mParent; 235 private final double mStart; 236 private final double mSpan; 237 private double mSubValue; 238 private double mSubCoef; 239 240 /** 241 * Creates a new sub task monitor which will work for the given range [start, start+span] 242 * in its parent. 243 * 244 * @param taskMonitor The ProgressTask root 245 * @param parent The immediate parent. Can be the null or another sub task monitor. 246 * @param start The start value in the root's coordinates 247 * @param span The span value in the root's coordinates 248 */ SubTaskMonitor(TaskMonitorImpl taskMonitor, ISubTaskMonitor parent, double start, double span)249 public SubTaskMonitor(TaskMonitorImpl taskMonitor, 250 ISubTaskMonitor parent, 251 double start, 252 double span) { 253 mRoot = taskMonitor; 254 mParent = parent; 255 mStart = start; 256 mSpan = span; 257 mSubValue = start; 258 } 259 260 @Override isCancelRequested()261 public boolean isCancelRequested() { 262 return mRoot.isCancelRequested(); 263 } 264 265 @Override setDescription(String format, Object... args)266 public void setDescription(String format, Object... args) { 267 mRoot.setDescription(format, args); 268 } 269 270 @Override log(String format, Object... args)271 public void log(String format, Object... args) { 272 mRoot.log(format, args); 273 } 274 275 @Override logError(String format, Object... args)276 public void logError(String format, Object... args) { 277 mRoot.logError(format, args); 278 } 279 280 @Override logVerbose(String format, Object... args)281 public void logVerbose(String format, Object... args) { 282 mRoot.logVerbose(format, args); 283 } 284 285 @Override setProgressMax(int max)286 public void setProgressMax(int max) { 287 assert max > 0; 288 mSubCoef = max > 0 ? mSpan / max : 0; 289 assert mSubCoef > 0; 290 } 291 292 @Override getProgressMax()293 public int getProgressMax() { 294 return mSubCoef > 0 ? (int) (mSpan / mSubCoef) : 0; 295 } 296 297 @Override getProgress()298 public int getProgress() { 299 // subCoef can be 0 if setProgressMax() and incProgress() haven't been called yet 300 assert mSubValue == mStart || mSubCoef > 0; 301 return mSubCoef > 0 ? (int)((mSubValue - mStart) / mSubCoef) : 0; 302 } 303 304 @Override incProgress(int delta)305 public void incProgress(int delta) { 306 if (delta > 0 && mSubCoef > 0) { 307 subIncProgress(delta * mSubCoef); 308 } 309 } 310 311 @Override subIncProgress(double realDelta)312 public void subIncProgress(double realDelta) { 313 mSubValue += realDelta; 314 if (mParent != null) { 315 mParent.subIncProgress(realDelta); 316 } else { 317 mRoot.internalIncProgress(realDelta); 318 } 319 } 320 321 @Override displayPrompt(String title, String message)322 public boolean displayPrompt(String title, String message) { 323 return mRoot.displayPrompt(title, message); 324 } 325 326 @Override displayLoginCredentialsPrompt(String title, String message)327 public UserCredentials displayLoginCredentialsPrompt(String title, String message) { 328 return mRoot.displayLoginCredentialsPrompt(title, message); 329 } 330 331 @Override createSubMonitor(int tickCount)332 public ITaskMonitor createSubMonitor(int tickCount) { 333 assert mSubCoef > 0; 334 assert tickCount > 0; 335 return new SubTaskMonitor(mRoot, 336 this, 337 mSubValue, 338 tickCount * mSubCoef); 339 } 340 341 // ----- ISdkLog interface ---- 342 343 @Override error(Throwable throwable, String errorFormat, Object... arg)344 public void error(Throwable throwable, String errorFormat, Object... arg) { 345 mRoot.error(throwable, errorFormat, arg); 346 } 347 348 @Override warning(String warningFormat, Object... arg)349 public void warning(String warningFormat, Object... arg) { 350 mRoot.warning(warningFormat, arg); 351 } 352 353 @Override printf(String msgFormat, Object... arg)354 public void printf(String msgFormat, Object... arg) { 355 mRoot.printf(msgFormat, arg); 356 } 357 } 358 } 359