Commit b5e78d70 authored by Evan W. Patton's avatar Evan W. Patton Committed by Jeffrey I. Schiller

Make MediaUtil.getBitmapDrawable asynchronous

When the minSdkVersion is >= 10 and the user attempts to set an image
to a non-file URL, the Android runtime will throw an
android.os.NetworkOnMainThreadException. This commit changes the
behavior of MediaUtil.getBitmapDrawable to an asynchronous design that
takes a callback that will be triggered after the bitmap has been
loaded. If an exception occurs, an onException callback will be
used. Other failures are reported via the onFailure callback. Due to
the change to AsyncCallbackPair, this change also affects a number of
other components that may or may not have been performing network
access on the main thread.

Testing of this change should focus on the following components:
 * ButtonBase and its descendants
 * Canvas
 * Form
 * GameClient
 * HVArrangement and its descendants
 * Image
 * ImageSprite
 * MediaStore
 * TinyWebDB
 * Voting

Change-Id: Ib9bd0a0a929b26ad44eeda58a7c637398dd70219
parent 8cbe40cf
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2016 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -13,12 +13,15 @@ import com.google.appinventor.components.annotations.SimpleObject;
import com.google.appinventor.components.annotations.SimpleProperty;
import com.google.appinventor.components.annotations.UsesPermissions;
import com.google.appinventor.components.common.PropertyTypeConstants;
import com.google.appinventor.components.runtime.util.AsyncCallbackPair;
import com.google.appinventor.components.runtime.util.ErrorMessages;
import com.google.appinventor.components.runtime.util.MediaUtil;
import com.google.appinventor.components.runtime.util.TextViewUtil;
import com.google.appinventor.components.runtime.util.ViewUtil;
import android.view.MotionEvent;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
......@@ -30,8 +33,6 @@ import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.View.OnLongClickListener;
import java.io.IOException;
/**
* Underlying base class for click-based components, not directly accessible to Simple programmers.
*
......@@ -314,17 +315,41 @@ public abstract class ButtonBase extends AndroidViewComponent
// Load image from file.
if (imagePath.length() > 0) {
try {
backgroundImageDrawable = MediaUtil.getBitmapDrawable(container.$form(), imagePath);
} catch (IOException ioe) {
// TODO(user): Maybe raise Form.ErrorOccurred.
Log.e(LOG_TAG, "Unable to load " + imagePath);
// Fall through with a value of null for backgroundImageDrawable.
}
}
MediaUtil.getBitmapDrawableAsync(container.$form(), imagePath, new AsyncCallbackPair<BitmapDrawable>() {
@Override
public void onFailure(String message) {
Log.w(LOG_TAG, "Error loading bitmap for button: " + message);
container.$form().dispatchErrorOccurredEvent(ButtonBase.this, "Image", ErrorMessages.ERROR_CANNOT_READ_FILE, imagePath);
container.$form().runOnUiThread(new Runnable() {
public void run() {
updateAppearance();
}
});
}
// Update the appearance based on the new value of backgroundImageDrawable.
updateAppearance();
@Override
public void onException(Exception e) {
Log.w(LOG_TAG, "Error loading bitmap for button", e);
container.$form().dispatchErrorOccurredEvent(ButtonBase.this, "Image", ErrorMessages.ERROR_CANNOT_READ_FILE, imagePath);
container.$form().runOnUiThread(new Runnable() {
public void run() {
updateAppearance();
}
});
}
@Override
public void onSuccess(BitmapDrawable result) {
backgroundImageDrawable = result;
// Update the appearance based on the new value of backgroundImageDrawable.
container.$form().runOnUiThread(new Runnable() {
public void run() {
updateAppearance();
}
});
}
});
}
}
/**
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2016 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -21,6 +21,7 @@ import com.google.appinventor.components.common.ComponentConstants;
import com.google.appinventor.components.common.PropertyTypeConstants;
import com.google.appinventor.components.common.YaVersion;
import com.google.appinventor.components.runtime.collect.Sets;
import com.google.appinventor.components.runtime.util.AsyncCallbackPair;
import com.google.appinventor.components.runtime.util.BoundingBox;
import com.google.appinventor.components.runtime.util.ErrorMessages;
import com.google.appinventor.components.runtime.util.FileUtil;
......@@ -548,16 +549,46 @@ public final class Canvas extends AndroidViewComponent implements ComponentConta
scaledBackgroundBitmap = null;
if (!TextUtils.isEmpty(backgroundImagePath)) {
try {
backgroundDrawable = MediaUtil.getBitmapDrawable(container.$form(), backgroundImagePath);
} catch (IOException ioe) {
Log.e(LOG_TAG, "Unable to load " + backgroundImagePath);
}
}
MediaUtil.getBitmapDrawableAsync(container.$form(), backgroundImagePath, new AsyncCallbackPair<BitmapDrawable>() {
@Override
public void onFailure(String message) {
Log.w(LOG_TAG, "Error loading background for canvas: " + message);
container.$form().dispatchErrorOccurredEvent(Canvas.this, "BackgroundImage", ErrorMessages.ERROR_CANNOT_READ_FILE, backgroundImagePath);
container.$form().runOnUiThread(new Runnable() {
public void run() {
setBackground();
clearDrawingLayer(); // will call invalidate()
}
});
}
setBackground();
@Override
public void onException(Exception e) {
Log.w(LOG_TAG, "Error loading background for canvas", e);
container.$form().dispatchErrorOccurredEvent(Canvas.this, "BackgroundImage", ErrorMessages.ERROR_CANNOT_READ_FILE, backgroundImagePath);
container.$form().runOnUiThread(new Runnable() {
public void run() {
setBackground();
clearDrawingLayer(); // will call invalidate()
}
});
}
clearDrawingLayer(); // will call invalidate()
@Override
public void onSuccess(BitmapDrawable result) {
backgroundDrawable = result;
container.$form().runOnUiThread(new Runnable() {
public void run() {
setBackground();
clearDrawingLayer(); // will call invalidate()
}
});
}
});
} else {
setBackground();
clearDrawingLayer(); // will call invalidate()
}
}
private void setBackground() {
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2016 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.components.runtime;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
......@@ -26,6 +25,7 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.PorterDuff;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
......@@ -61,9 +61,9 @@ import com.google.appinventor.components.runtime.collect.Lists;
import com.google.appinventor.components.runtime.collect.Maps;
import com.google.appinventor.components.runtime.collect.Sets;
import com.google.appinventor.components.runtime.multidex.MultiDex;
import com.google.appinventor.components.runtime.multidex.MultiDexApplication;
import com.google.appinventor.components.runtime.util.AlignmentUtil;
import com.google.appinventor.components.runtime.util.AnimationUtil;
import com.google.appinventor.components.runtime.util.AsyncCallbackPair;
import com.google.appinventor.components.runtime.util.ErrorMessages;
import com.google.appinventor.components.runtime.util.FullScreenVideoUtil;
import com.google.appinventor.components.runtime.util.JsonUtil;
......@@ -971,13 +971,41 @@ public class Form extends Activity
public void BackgroundImage(String path) {
backgroundImagePath = (path == null) ? "" : path;
try {
backgroundDrawable = MediaUtil.getBitmapDrawable(this, backgroundImagePath);
} catch (IOException ioe) {
Log.e(LOG_TAG, "Unable to load " + backgroundImagePath);
backgroundDrawable = null;
}
setBackground(frameLayout);
MediaUtil.getBitmapDrawableAsync(this, backgroundImagePath, new AsyncCallbackPair<BitmapDrawable>() {
@Override
public void onFailure(String message) {
Log.w(LOG_TAG, "Error loading background for form: " + message);
Form.this.dispatchErrorOccurredEvent(Form.this, "BackgroundImage", ErrorMessages.ERROR_CANNOT_READ_FILE, backgroundImagePath);
backgroundDrawable = null;
androidUIHandler.post(new Runnable() {
public void run() {
setBackground(frameLayout);
}
});
}
@Override
public void onException(Exception e) {
Log.w(LOG_TAG, "Error loading background for form", e);
Form.this.dispatchErrorOccurredEvent(Form.this, "BackgroundImage", ErrorMessages.ERROR_CANNOT_READ_FILE, backgroundImagePath);
backgroundDrawable = null;
androidUIHandler.post(new Runnable() {
public void run() {
setBackground(frameLayout);
}
});
}
@Override
public void onSuccess(BitmapDrawable result) {
backgroundDrawable = result;
androidUIHandler.post(new Runnable() {
public void run() {
setBackground(frameLayout);
}
});
}
});
}
/**
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2016 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -600,7 +600,15 @@ public class GameClient extends AndroidNonvisibleComponent
@SimpleEvent(description = "Indicates that an error occurred " +
"while communicating with the web server.")
public void WebServiceError(final String functionName, final String message) {
Log.e(LOG_TAG, "WebServiceError: " + message);
WebServiceError(functionName, message, null);
}
public void WebServiceError(final String functionName, final String message, Exception e) {
if (e != null) {
Log.e(LOG_TAG, "WebServiceError: " + message, e);
} else {
Log.e(LOG_TAG, "WebServiceError: " + message);
}
androidUIHandler.post(new Runnable() {
public void run() {
EventDispatcher.dispatchEvent(GameClient.this, "WebServiceError", functionName, message);
......@@ -630,6 +638,9 @@ public class GameClient extends AndroidNonvisibleComponent
processInstanceLists(response);
FunctionCompleted("GetInstanceLists");
}
public void onException(final Exception e) {
WebServiceError("GetInstanceLists", "Failed to get up to date instance lists.", e);
}
public void onFailure(final String message) {
WebServiceError("GetInstanceLists", "Failed to get up to date instance lists.");
}
......@@ -735,7 +746,9 @@ public class GameClient extends AndroidNonvisibleComponent
}
FunctionCompleted("GetMessages");
}
public void onException(Exception e) {
WebServiceError("GetMessages", e.getMessage(), e);
}
public void onFailure(String message) {
WebServiceError("GetMessages", message);
}
......@@ -794,6 +807,9 @@ public class GameClient extends AndroidNonvisibleComponent
}
FunctionCompleted("Invite");
}
public void onException(final Exception e) {
WebServiceError("Invite", e.getMessage(), e);
}
public void onFailure(final String message) {
WebServiceError("Invite", message);
}
......@@ -843,6 +859,9 @@ public class GameClient extends AndroidNonvisibleComponent
processInstanceLists(response);
FunctionCompleted("LeaveInstance");
}
public void onException(final Exception e) {
WebServiceError("LeaveInstance", e.getMessage(), e);
}
public void onFailure(final String message) {
WebServiceError("LeaveInstance", message);
}
......@@ -891,6 +910,9 @@ public class GameClient extends AndroidNonvisibleComponent
NewInstanceMade(InstanceId());
FunctionCompleted("MakeNewInstance");
}
public void onException(final Exception e) {
WebServiceError("MakeNewInstance", e.getMessage(), e);
}
public void onFailure(final String message) {
WebServiceError("MakeNewInstance", message);
}
......@@ -936,6 +958,9 @@ public class GameClient extends AndroidNonvisibleComponent
public void onSuccess(final JSONObject response) {
FunctionCompleted("SendMessage");
}
public void onException(final Exception e) {
WebServiceError("SendMessage", e.getMessage(), e);
}
public void onFailure(final String message) {
WebServiceError("SendMessage", message);
}
......@@ -991,7 +1016,10 @@ public class GameClient extends AndroidNonvisibleComponent
}
FunctionCompleted("ServerCommand");
}
public void onException(Exception e) {
ServerCommandFailure(command, arguments);
WebServiceError("ServerCommand", e.getMessage(), e);
}
public void onFailure(String message) {
ServerCommandFailure(command, arguments);
WebServiceError("ServerCommand", message);
......@@ -1040,6 +1068,9 @@ public class GameClient extends AndroidNonvisibleComponent
processInstanceLists(response);
FunctionCompleted("SetInstance");
}
public void onException(final Exception e) {
WebServiceError("SetInstance", e.getMessage(), e);
}
public void onFailure(final String message) {
WebServiceError("SetInstance", message);
}
......@@ -1080,6 +1111,9 @@ public class GameClient extends AndroidNonvisibleComponent
public void onSuccess(final JSONObject response) {
FunctionCompleted("SetLeader");
}
public void onException(final Exception e) {
WebServiceError("SetLeader", e.getMessage(), e);
}
public void onFailure(final String message) {
WebServiceError("SetLeader", message);
}
......@@ -1170,6 +1204,9 @@ public class GameClient extends AndroidNonvisibleComponent
callback.onFailure("Failed to parse JSON response to command " + commandName);
}
}
public void onException(Exception e) {
callback.onException(e);
}
public void onFailure(String failureMessage) {
Log.d(LOG_TAG, "Posting to server failed for " + commandName + " with arguments " +
params + "\n Failure message: " + failureMessage);
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2016 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.components.runtime;
import android.app.Activity;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
......@@ -30,16 +30,11 @@ import com.google.appinventor.components.common.ComponentConstants;
import com.google.appinventor.components.common.PropertyTypeConstants;
import com.google.appinventor.components.runtime.util.AlignmentUtil;
import com.google.appinventor.components.runtime.util.AsyncCallbackPair;
import com.google.appinventor.components.runtime.util.ErrorMessages;
import com.google.appinventor.components.runtime.util.MediaUtil;
import com.google.appinventor.components.runtime.util.ViewUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* A container for components that arranges them linearly, either
* horizontally or vertically.
......@@ -352,15 +347,33 @@ public class HVArrangement extends AndroidViewComponent implements Component, Co
// Load image from file.
if (imagePath.length() > 0) {
try {
backgroundImageDrawable = MediaUtil.getBitmapDrawable(container.$form(), imagePath);
} catch (IOException ioe) {
// Fall through with a value of null for backgroundImageDrawable.
MediaUtil.getBitmapDrawableAsync(container.$form(), imagePath, new AsyncCallbackPair<BitmapDrawable>() {
@Override
public void onFailure(String message) {
Log.w(LOG_TAG, "Error loading background for canvas: " + message);
container.$form().dispatchErrorOccurredEvent(HVArrangement.this, "Image", ErrorMessages.ERROR_CANNOT_READ_FILE, imagePath);
}
}
// Update the appearance based on the new value of backgroundImageDrawable.
updateAppearance();
@Override
public void onException(Exception e) {
Log.w(LOG_TAG, "Error loading background for canvas", e);
container.$form().dispatchErrorOccurredEvent(HVArrangement.this, "Image", ErrorMessages.ERROR_CANNOT_READ_FILE, imagePath);
}
@Override
public void onSuccess(BitmapDrawable result) {
backgroundImageDrawable = result;
container.$form().runOnUiThread(new Runnable() {
public void run() {
updateAppearance();
}
});
}
});
} else {
// Update the appearance based on the new value of backgroundImageDrawable.
updateAppearance();
}
}
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2016 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -9,7 +9,6 @@ package com.google.appinventor.components.runtime;
import com.google.appinventor.components.annotations.DesignerComponent;
import com.google.appinventor.components.annotations.DesignerProperty;
import com.google.appinventor.components.annotations.PropertyCategory;
import com.google.appinventor.components.annotations.SimpleFunction;
import com.google.appinventor.components.annotations.SimpleObject;
import com.google.appinventor.components.annotations.SimpleProperty;
import com.google.appinventor.components.annotations.UsesPermissions;
......@@ -18,19 +17,19 @@ import com.google.appinventor.components.common.PropertyTypeConstants;
import com.google.appinventor.components.common.YaVersion;
import com.google.appinventor.components.runtime.errors.IllegalArgumentError;
import com.google.appinventor.components.runtime.util.AnimationUtil;
import com.google.appinventor.components.runtime.util.AsyncCallbackPair;
import com.google.appinventor.components.runtime.util.ErrorMessages;
import com.google.appinventor.components.runtime.util.HoneycombUtil;
import com.google.appinventor.components.runtime.util.MediaUtil;
import com.google.appinventor.components.runtime.util.SdkLevel;
import com.google.appinventor.components.runtime.util.ViewUtil;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import java.io.IOException;
/**
* Component for displaying images and animations.
*
......@@ -43,6 +42,7 @@ import java.io.IOException;
@SimpleObject
@UsesPermissions(permissionNames = "android.permission.INTERNET")
public final class Image extends AndroidViewComponent {
private static final String LOG_TAG = Image.class.getSimpleName();
private final ImageView view;
......@@ -104,15 +104,38 @@ public final class Image extends AndroidViewComponent {
public void Picture(String path) {
picturePath = (path == null) ? "" : path;
Drawable drawable;
try {
drawable = MediaUtil.getBitmapDrawable(container.$form(), picturePath);
} catch (IOException ioe) {
Log.e("Image", "Unable to load " + picturePath);
drawable = null;
}
MediaUtil.getBitmapDrawableAsync(container.$form(), picturePath, new AsyncCallbackPair<BitmapDrawable>() {
@Override
public void onFailure(String message) {
Log.w(LOG_TAG, "Error loading background for image: " + message);
container.$form().dispatchErrorOccurredEvent(Image.this, "Picture", ErrorMessages.ERROR_CANNOT_READ_FILE, picturePath);
container.$form().runOnUiThread(new Runnable() {
public void run() {
ViewUtil.setImage(view, null);
}
});
}
ViewUtil.setImage(view, drawable);
@Override
public void onException(Exception e) {
Log.w(LOG_TAG, "Error loading background for image", e);
container.$form().dispatchErrorOccurredEvent(Image.this, "Picture", ErrorMessages.ERROR_CANNOT_READ_FILE, picturePath);
container.$form().runOnUiThread(new Runnable() {
public void run() {
ViewUtil.setImage(view, null);
}
});
}
@Override
public void onSuccess(final BitmapDrawable result) {
container.$form().runOnUiThread(new Runnable() {
public void run() {
ViewUtil.setImage(view, result);
}
});
}
});
}
/**
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2016 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.components.runtime;
import java.io.IOException;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.util.Log;
......@@ -21,6 +18,8 @@ import com.google.appinventor.components.annotations.UsesPermissions;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.common.PropertyTypeConstants;
import com.google.appinventor.components.common.YaVersion;
import com.google.appinventor.components.runtime.util.AsyncCallbackPair;
import com.google.appinventor.components.runtime.util.ErrorMessages;
import com.google.appinventor.components.runtime.util.MediaUtil;
/**
......@@ -51,6 +50,7 @@ import com.google.appinventor.components.runtime.util.MediaUtil;
@SimpleObject
@UsesPermissions(permissionNames = "android.permission.INTERNET")
public class ImageSprite extends Sprite {
private static final String LOG_TAG = ImageSprite.class.getSimpleName();
private final Form form;
private BitmapDrawable drawable;
private int widthHint = LENGTH_PREFERRED;
......@@ -125,14 +125,41 @@ public class ImageSprite extends Sprite {
@SimpleProperty
public void Picture(String path) {
picturePath = (path == null) ? "" : path;
try {
drawable = MediaUtil.getBitmapDrawable(form, picturePath);
} catch (IOException ioe) {
Log.e("ImageSprite", "Unable to load " + picturePath);
drawable = null;
}
// note: drawable can be null!
registerChange();
MediaUtil.getBitmapDrawableAsync(form, picturePath, new AsyncCallbackPair<BitmapDrawable>() {
@Override
public void onFailure(String message) {
Log.w(LOG_TAG, "Error loading background for canvas: " + message);
drawable = null;
form.dispatchErrorOccurredEvent(ImageSprite.this, "Picture", ErrorMessages.ERROR_CANNOT_READ_FILE, picturePath);
form.runOnUiThread(new Runnable() {
public void run() {
registerChange();
}
});
}
@Override
public void onException(Exception e) {
Log.w("ImageSprite", "Unable to load " + picturePath, e);
drawable = null;
form.dispatchErrorOccurredEvent(ImageSprite.this, "Picture", ErrorMessages.ERROR_CANNOT_READ_FILE, picturePath);
form.runOnUiThread(new Runnable() {
public void run() {
registerChange();
}
});
}
@Override
public void onSuccess(BitmapDrawable result) {
drawable = result;
form.runOnUiThread(new Runnable() {
public void run() {
registerChange();
}
});
}
});
}
// The actual width/height of an ImageSprite whose Width/Height property is set to Automatic or
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2016 MIT, All rights reserved
// Released under the MIT License https://raw.github.com/mit-cml/app-inventor/master/mitlicense.txt
package com.google.appinventor.components.runtime;
import android.os.Handler;
import android.util.Log;
import com.google.appinventor.components.annotations.DesignerComponent;
import com.google.appinventor.components.annotations.DesignerProperty;
......@@ -123,6 +124,14 @@ public final class MediaStore extends AndroidNonvisibleComponent implements Comp
}
});
}
public void onException(final Exception e) {
androidUIHandler.post(new Runnable() {
public void run() {
Log.e(LOG_TAG_COMPONENT, "Exception in PostMedia", e);
WebServiceError(e.getMessage());
}
});
}
public void onFailure(final String message) {
androidUIHandler.post(new Runnable() {
public void run() {
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2016 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -25,6 +25,7 @@ import com.google.appinventor.components.runtime.util.JsonUtil;
import com.google.appinventor.components.runtime.util.WebServiceUtil;
import android.os.Handler;
import android.util.Log;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
......@@ -196,6 +197,14 @@ public class TinyWebDB extends AndroidNonvisibleComponent implements Component {
}
});
}
public void onException(final Exception e) {
androidUIHandler.post(new Runnable() {
public void run() {
Log.e(LOG_TAG, "Exception in WebService", e);
WebServiceError(e.getMessage());
}
});
}
public void onFailure(final String message) {
// Pass any failure message from the Web service command back
// to the error handler.
......@@ -307,6 +316,14 @@ public class TinyWebDB extends AndroidNonvisibleComponent implements Component {
}
}
}
public void onException(final Exception e) {
androidUIHandler.post(new Runnable() {
public void run() {
Log.e(LOG_TAG, "Exception in TinyWebDB", e);
WebServiceError(e.getMessage());
}
});
}
public void onFailure(final String message) {
// Signal a Web error event to indicate that there was no response
// to this request for a value. Note that this needs to be posted to the UI
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2016 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -319,6 +319,14 @@ public class Voting extends AndroidNonvisibleComponent implements Component {
}
}
}
public void onException(final Exception e) {
androidUIHandler.post(new Runnable() {
public void run() {
Log.e(LOG_TAG, "Exception in Voting component: ", e);
WebServiceError(e.getMessage());
}
});
}
public void onFailure(final String message) {
Log.w(LOG_TAG, "postRequestBallot Failure " + message);
androidUIHandler.post(new Runnable() {
......@@ -395,6 +403,14 @@ public class Voting extends AndroidNonvisibleComponent implements Component {
}
});
}
public void onException(final Exception e) {
androidUIHandler.post(new Runnable() {
public void run() {
Log.e(LOG_TAG, "Exception in Voting component: ", e);
WebServiceError(e.getMessage());
}
});
}
public void onFailure(final String message) {
Log.w(LOG_TAG, "postSendBallot Failure " + message);
androidUIHandler.post(new Runnable() {
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2016 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -28,6 +28,13 @@ package com.google.appinventor.components.runtime.util;
*/
void onFailure(String message);
/**
* Called when an asynchronous call fails to complete due to an exception.
*
* @param e An exception thrown during asynchronous operation.
*/
void onException(Exception e);
/**
* Called when an asynchronous call completes successfully.
*
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2016 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
......@@ -98,6 +98,9 @@ public class WebServiceUtil {
callback.onFailure(e.getMessage());
}
}
public void onException(Exception e) {
callback.onException(e);
}
public void onFailure(String failureMessage) {
callback.onFailure(failureMessage);
}
......@@ -117,15 +120,18 @@ public class WebServiceUtil {
* on success.
*/
public void postCommandReturningObject(final String serviceURL,final String commandName,
List<NameValuePair> params, final AsyncCallbackPair<JSONObject> callback) {
List<NameValuePair> params, final AsyncCallbackPair<JSONObject> callback) {
AsyncCallbackPair<String> thisCallback = new AsyncCallbackPair<String>() {
public void onSuccess(String httpResponseString) {
public void onSuccess(String httpResponseString) {
try {
callback.onSuccess(new JSONObject(httpResponseString));
} catch (JSONException e) {
callback.onFailure(e.getMessage());
}
}
public void onException(Exception e) {
callback.onException(e);
}
public void onFailure(String failureMessage) {
callback.onFailure(failureMessage);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment