/** * Cancel execution if possible. This is called on the Worker thread * * <p>Do not override this unless you also call super.cancel(boolean). * * <p>Override onCanceled() is the normal notification location, and is called from the UI thread * with Task state updates handled for you. * * @param mayInterruptIfRunning (not yet supported) * @return */ public synchronized boolean cancel(final boolean mayInterruptIfRunning) { boolean canceled = false; // #debug L.i("Begin explicit cancel task", "status=" + this.getStatusString() + " " + this); switch (status) { case EXEC_STARTED: if (mayInterruptIfRunning && Worker.interruptWorkable(this)) { setStatus(CANCELED); canceled = true; } break; case EXEC_FINISHED: case UI_RUN_FINISHED: // #debug L.i( "Attempt to cancel Task after run completes, suspicious but may be normal", this.toString()); break; default: setStatus(CANCELED); canceled = true; } return canceled; }
protected Object exec(Object in) { if (in != null) { // #debug L.i("Load feed success, type=" + getType, search); scrollY = 0; imageObjectModel.removeAllElements(); images.clear(); L.i("Vector in", in.toString()); final Vector newModel = (Vector) in; for (int i = 0; i < newModel.size(); i++) { imageObjectModel.addElement(newModel.elementAt(i)); String thumbUrl = ((PicasaImageObject) imageObjectModel.elementAt(i)).thumbUrl; try { PicasaStorage.imageCache.prefetch(thumbUrl); } catch (FlashDatabaseException e) { L.e("Could not fetch image", thumbUrl, e); } } top = -((imageObjectModel.size() * imageSide) / 2 - getHeight() / 2) + imageSide - 20; stopSpinner(); } else { L.i("Variable in is null", ""); } return in; }
/** * Wait for a maximum of timeout milliseconds for the UITask to complete if needed and then also * complete the followup action on the user interface thread. * * <p>You will receive a debug time warning if you are currently on the UI thread and the timeout * value is greater than 100ms. * * @param timeout in milliseconds * @return final evaluation result of the Task * @throws InterruptedException - task was running when it was explicitly canceled by another * thread * @throws CancellationException - task was explicitly canceled by another thread * @throws ExecutionException - an uncaught exception was thrown * @throws TimeoutException - UITask failed to complete within timeout milliseconds */ public final Object joinUI(long timeout) throws InterruptedException, CancellationException, ExecutionException, TimeoutException { if (!(this instanceof UITask)) { throw new ClassCastException("Can not joinUI() unless Task is a UITask"); } long t = System.currentTimeMillis(); join(timeout); synchronized (this) { if (status < UI_RUN_FINISHED) { // #debug L.i("Start joinUI wait", "status=" + getStatusString()); timeout -= System.currentTimeMillis() - t; while (timeout > 0) { final long t2 = System.currentTimeMillis(); wait(timeout); if (status == UI_RUN_FINISHED) { break; } timeout -= System.currentTimeMillis() - t2; } // #debug L.i("End joinUI wait", "status=" + getStatusString()); if (status < UI_RUN_FINISHED) { throw new TimeoutException("JoinUI(" + timeout + ") failed to complete quickly enough"); } } return value; } }
/** * Get the cache singleton associated with these parameters. * * @param priority * @param cacheType * @param startupTask * @return * @throws FlashDatabaseException */ public FlashCache getFlashCache( final char priority, final int cacheType, final FlashCache.StartupTask startupTask) throws FlashDatabaseException { switch (cacheType) { case PlatformUtils.PHONE_DATABASE_CACHE: try { return new RMSFastCache(priority, startupTask); } catch (Exception e) { // #debug L.e( "Can not create flash cache, will attempt delete and re-init one time", "" + priority, e); RMSFastCache.deleteDataFiles(priority); try { final RMSFastCache cache = new RMSFastCache(priority, startupTask); // #debug L.i( "After deleting the files giving and error, we successfully created flash cache", "" + priority); return cache; } catch (Exception e2) { throw new FlashDatabaseException("Can not create flash cache: " + e2); } } default: throw new IllegalArgumentException( "Unsupported cache type " + cacheType + ": only PlatformAdapter.PHONE_DATABASE_CACHE is supported at this time"); } }
/** * Initializes the storage. * * @param width The width of the screen. This is used to determine how large images should be. */ public static synchronized void init(final int width) { if (feedCache == null) { final ImageCacheView imageCacheView = PlatformUtils.getInstance().getImageCacheView(); screenWidth = width; if (screenWidth < 256) { imageSide = 128; // Must be supported picasa thumb size imageSize = 288; // Image max size to get suitable sized images from picasa } else { imageSide = 256; // Must be supported thumb size in picasa imageSize = 720; // Picasa size for "fullsize" images } imageCacheView.setMaxSize(width, width); try { imageCache = StaticWebCache.getWebCache( '4', PlatformUtils.PHONE_DATABASE_CACHE, imageCacheView, new StaticWebCache.HttpTaskFactory(), null); } catch (FlashDatabaseException e) { L.e("Could not initialize imageCache.", "", e); } try { feedCache = StaticWebCache.getWebCache('5', (CacheView) new ImageObjectTypeHandler()); } catch (FlashDatabaseException e) { L.e("Could not initialize feedCache.", "", e); } thumbSize = imageSide + "c"; // c is for cropped, ensures image proportions urlOptions = "?alt=json&kind=photo&max-results=" + NR_OF_FEATURED + "&thumbsize=" + thumbSize + "&fields=entry(title,author(name),updated,media:group)" + "&imgmax=" + imageSize; featURL = "http://picasaweb.google.com/data/feed/base/featured" + urlOptions; searchURL = "http://picasaweb.google.com/data/feed/base/all" + urlOptions + "&q="; } }
/** * You can call this as the return statement of your overriding method once you have set the * result * * @return */ public final Object exec(Object in) { Object out = in; try { synchronized (this) { if (in == null) { in = value; } else { value = in; } if (status == Task.CANCELED || status == Task.EXCEPTION) { throw new IllegalStateException( this.getStatusString() + " state can not be executed: " + this); } else if (status != Task.EXEC_STARTED) { setStatus(Task.EXEC_STARTED); } } out = doInBackground(in); final boolean doRun; final Task t; synchronized (this) { value = out; doRun = status == EXEC_STARTED; if (doRun) { setStatus(EXEC_FINISHED); } t = chainedTask; } if (this instanceof UITask && doRun) { PlatformUtils.runOnUiThread((UITask) this); } if (t != null) { // #debug L.i("Begin exec chained task", chainedTask.toString() + " INPUT: " + out); t.exec(out); // #debug L.i("End exec chained task", chainedTask.toString()); } } catch (final Throwable t) { // #debug L.e("Unhandled task exception", this.toString(), t); setStatus(EXCEPTION); } return out; }
/** * Add a Task (or UITAsk, etc) which will run immediately after the present Task and on the same * Worker thread. * * <p>The output result of the present task is fed as the input to doInBackground() on the * nextTask, so any processing changes can propagated forward if the nextTask is so designed. This * Task behavior may thus be slightly different from the first Task in the chain, which by default * receives "null" as the input argument unless setValue() is called before fork()ing the first * task in the chain. * * @param nextTask * @return nextTask */ public final synchronized Task chain(final Task nextTask) { // #mdebug if (nextTask == null) { L.i("WARNING", "chain(null) is probably a mistake- no effect"); } // #enddebug this.chainedTask = nextTask; return nextTask; }
public void onCanceled() { // #debug L.i("Load feed canceled, type=" + getType, search); if (getType == StaticWebCache.GET_LOCAL) { imageObjectModel.removeAllElements(); images.clear(); top = -getHeight(); } stopSpinner(); }
private static void doJoinAll(final Task[] tasks, final long timeout, final boolean joinUI) throws InterruptedException, CancellationException, ExecutionException, TimeoutException { if (tasks == null) { throw new IllegalArgumentException("Can not joinAll(), list of tasks to join is null"); } if (timeout < 0) { throw new IllegalArgumentException("Can not joinAll() with timeout < 0: timeout=" + timeout); } // #mdebug if (PlatformUtils.isUIThread() && timeout > 100) { L.i("WARNING- slow Task.joinAll() on UI Thread", "timeout=" + timeout); } // #enddebug // #debug L.i("Start joinAll(" + timeout + ")", "numberOfTasks=" + tasks.length); long timeLeft = Long.MAX_VALUE; try { final long startTime = System.currentTimeMillis(); for (int i = 0; i < tasks.length; i++) { final Task task = tasks[i]; timeLeft = startTime + timeout - System.currentTimeMillis(); if (timeLeft <= 0) { throw new TimeoutException("joinAll(" + timeout + ") timout exceeded (" + timeLeft + ")"); } if (joinUI && task instanceof UITask) { task.joinUI(timeout); } else { task.join(timeout); } } } finally { // #debug L.i( "End joinAll(" + timeout + ")", "numberOfTasks=" + tasks.length + " timeElapsed=" + (timeout - timeLeft)); } }
/** * @param search * @param getType * @return */ public Task loadFeed(final String search, final int getType) { // #debug L.i("loadFeed", search); final Task task = new LoadFeedTask(search, getType); PicasaStorage.getImageObjects(search, Task.HIGH_PRIORITY, getType, task); if (getType != StaticWebCache.GET_LOCAL) { startSpinner(); } return task; }
/** @see com.nokia.example.picasaviewer.ui.GestureCanvas#gestureTap(int, int) */ public boolean gestureTap(int startX, int startY) { boolean handled = false; if (!super.gestureTap(startX, startY)) { final int index = getItemIndex(startX, startY); if (index >= 0 && index < imageObjectModel.size()) { PicasaImageObject picasaImageObject = (PicasaImageObject) imageObjectModel.elementAt(index); PicasaStorage.setSelectedImage(picasaImageObject); // #debug L.i("select image", PicasaStorage.getSelectedImage().toString()); viewManager.showView(ViewManager.DETAILS_VIEW_INDEX); handled = true; } } return handled; }
/** * Change the status * * <p>You can only change status CANCELED or EXCEPTION to the READY state to explicitly indicate * you are going to re-use this Task. Note that Task re-use is generally not advised, but can be * valid if you have a special need such as performance when re-creating the Task is particularly * expensive. * * @param status */ public final void setStatus(final int status) { if (status < EXEC_PENDING || status > READY) { throw new IllegalArgumentException("setStatus(" + status + ") not allowed"); } final Task t; synchronized (this) { if ((this.status == CANCELED || this.status == EXCEPTION) && status != READY) { // #debug L.i( "State change from " + getStatusString() + " to " + Task.STATUS_STRINGS[status] + " is ignored", this.toString()); return; } this.status = status; this.notifyAll(); t = chainedTask; } if (status == CANCELED || status == EXCEPTION) { PlatformUtils.runOnUiThread( new Runnable() { public void run() { // #debug L.i("Task onCanceled()", Task.this.toString()); onCanceled(); } }); // Also cancel any chained Tasks expecting the output of this Task if (t != null) { t.cancel(false); } } }
/** * When parsing this RSS XML document, this indicates the body of an XML tag * * @param qname * @param chars * @param attributes */ protected synchronized void parseElement( final String qname, final String chars, final XMLAttributes attributes) { try { if (currentItem != null) { synchronized (currentItem) { if (qname.equals("title")) { currentItem.setTitle(chars); } else if (qname.equals("description")) { currentItem.setDescription(chars); } else if (qname.equals("link")) { currentItem.setLink(chars); } else if (qname.equals("pubDate")) { currentItem.setPubDate(chars); } else if (qname.equals("media:thumbnail")) { currentItem.setThumbnail((String) attributes.getValue("url")); } } } } catch (Exception e) { // #debug L.e("RSS parsing error", "qname=" + qname + " - chars=" + chars, e); } }
/** * This is executed on the UI thread * * <p>Override if needed, the default implementation does nothing except provide debug output. * * <p>Use getStatus() to distinguish between CANCELED and EXCEPTION states if necessary. */ protected void onCanceled() { // #debug L.i("Task canceled", this.toString()); }
/** * Wait for a maximum of timeout milliseconds for the Task to run and return it's evaluation * value, otherwise throw a TimeoutExeception. * * <p>Similar to get(), except the total wait() time if the AsyncTask has not completed is * explicitly limited to prevent long delays. * * <p>Never call join() from the UI thread with a timeout greater than 100ms. This is still bad * design and better handled with a chained Task or UITask. You will receive a debug warning, but * are not prevented from making longer join() calls from the user interface Thread. * * @param timeout in milliseconds * @return final evaluation result of the Task * @throws InterruptedException - task was running when it was explicitly canceled by another * thread * @throws CancellationException - task was explicitly canceled by another thread * @throws ExecutionException - an uncaught exception was thrown * @throws TimeoutException - UITask failed to complete within timeout milliseconds */ public final Object join(long timeout) throws InterruptedException, CancellationException, ExecutionException, TimeoutException { if (timeout < 0) { throw new IllegalArgumentException("Can not join() with timeout < 0: timeout=" + timeout); } // #mdebug if (PlatformUtils.isUIThread() && timeout > 100) { L.i("WARNING- slow Task.join() on UI Thread", "timeout=" + timeout + " " + this); } // #enddebug boolean doExec = false; Object r; synchronized (this) { // #debug L.i("Start join", "timeout=" + timeout + " " + this); switch (status) { case EXEC_PENDING: // #debug L.i("Start join of EXEC_PENDING task", "timeout=" + timeout + " " + this.toString()); if (Worker.tryUnfork(this)) { doExec = true; break; } // Continue to next state case READY: if (status == READY) { Worker.fork(this, Worker.HIGH_PRIORITY); } // Continue to next state case EXEC_STARTED: // #debug L.i("Start join wait()", "status=" + getStatusString()); do { final long t = System.currentTimeMillis(); wait(timeout); if (status == EXEC_FINISHED) { break; } if (status == CANCELED) { throw new CancellationException( "join() was to a Task which had already been canceled: " + this); } if (status == EXCEPTION) { throw new ExecutionException( "join() was to a Task which had already expereienced an uncaught runtime exception: " + this); } timeout -= System.currentTimeMillis() - t; } while (timeout > 0); // #debug L.i("End join wait()", "status=" + getStatusString()); if (status == EXEC_STARTED) { throw new TimeoutException( "Task was already started when join() was call and did not complete during " + timeout + " milliseconds"); } break; case CANCELED: throw new CancellationException( "join() was to a Task which was running but then canceled: " + this); case EXCEPTION: throw new ExecutionException( "join() was to a Task which had an uncaught exception: " + this); default:; } r = value; } if (doExec) { // #debug L.i( "Start exec() out-of-sequence exec() after join() and successful unfork()", this.toString()); r = exec(r); } return r; }
public Object convertToUseForm(Object key, byte[] bytes) { JSONObject responseJson; try { responseJson = new JSONObject(new String(bytes)); } catch (JSONException ex) { // #debug L.e("bytes are not a JSON object", featURL, ex); return null; } JSONArray entries = new JSONArray(); final Vector vector = new Vector(); try { final JSONObject feed = ((JSONObject) responseJson).getJSONObject("feed"); entries = feed.getJSONArray("entry"); } catch (JSONException e) { vector.addElement(new PicasaImageObject("No Results", "", "", "")); // #debug L.e("JSON no result", featURL, e); } for (int i = 0; i < entries.length(); i++) { try { final JSONObject jsonObject = entries.getJSONObject(i); final String title = jsonObject.getJSONObject("title").getString("$t"); final String author = jsonObject .getJSONArray("author") .getJSONObject(0) .getJSONObject("name") .getString("$t"); final String thumbUrl = jsonObject .getJSONObject("media$group") .getJSONArray("media$thumbnail") .getJSONObject(0) .getString("url"); final String imageUrl = jsonObject .getJSONObject("media$group") .getJSONArray("media$content") .getJSONObject(0) .getString("url"); // #mdebug L.i("JSON parsed title: ", title); L.i("JSON parsed author: ", author); L.i("JSON parsed thumb url: ", thumbUrl); L.i("JSON parsed image url: ", imageUrl); // #enddebug vector.addElement(new PicasaImageObject(title, author, thumbUrl, imageUrl)); } catch (JSONException e) { // #debug L.e("JSON item parse error", featURL, e); } } if (entries.length() == 0) { vector.addElement(new PicasaImageObject("No Results", "", "", "")); } return vector; }