Google Glass GDK CameraManager Intent - google-glass

Does anyone know if when you use the GDK Cameramanager Intent to take a picture, is there a way to not show the preview or close it automatically? Capturing an image for use in app and don't want to have to tap to accept.
I probably have missed something.
Thanks,

You can try this:
Intent localIntent = new Intent("com.google.glass.action.TAKE_PICTURE_FROM_SCREEN_OFF");
localIntent.putExtra("should_finish_turn_screen_off", true);
localIntent.putExtra("should_take_picture", true);
localIntent.putExtra("screenshot_file_path", pathToFile);
startActivity(localIntent);
It will close your preview automatically after few seconds.

try this...
private void takePicture() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 0);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 0 && resultCode == RESULT_OK) {
String picturePath=data.getStringExtra(CameraManager.EXTRA_PICTURE_FILE_PATH);
processPictureWhenReady(picturePath);
}
super.onActivityResult(requestCode, resultCode, data);
}
private void processPictureWhenReady(final String picturePath) {
final File pictureFile = new File(picturePath);
if (pictureFile.exists()) {
// The picture is ready; process it.
// Write your code here
} else {
final File parentDirectory = pictureFile.getParentFile();
FileObserver observer = new FileObserver(parentDirectory.getPath()) {
// Protect against additional pending events after CLOSE_WRITE is
// handled.
private boolean isFileWritten;
#Override
public void onEvent(int event, String path) {
if (!isFileWritten) {
// For safety, make sure that the file that was created in
// the directory is actually the one that we're expecting.
File affectedFile = new File(parentDirectory, path);
isFileWritten = (event == FileObserver.CLOSE_WRITE
&& affectedFile.equals(pictureFile));
if (isFileWritten) {
stopWatching();
// Now that the file is ready, recursively call
// processPictureWhenReady again (on the UI thread).
runOnUiThread(new Runnable() {
#Override
public void run() {
processPictureWhenReady(picturePath);
}
});
}
}
}};
observer.startWatching();
}
}

Related

Checkbox change other checkbox statement

I need to connect some Checkboxes, so when I click one it becomes checked and other become unchecked. My code right now looks like this.
Connect in class constructor:
connect(cb_thickness1,SIGNAL(stateChanged(int)),this,SLOT(cb_thickness1_isChecked()));
connect(cb_thickness2,SIGNAL(stateChanged(int)),this,SLOT(cb_thickness2_isChecked()));
connect(cb_thickness3,SIGNAL(stateChanged(int)),this,SLOT(cb_thickness3_isChecked()));
and slots
void MainWind::cb_thickness1_isChecked()
{
if(cb_thickness2->isChecked())
cb_thickness2->setChecked(false);
if(cb_thickness3->isChecked())
cb_thickness3->setChecked(false);
}
void MainWind::cb_thickness2_isChecked()
{
if(cb_thickness1->isChecked())
cb_thickness1->setChecked(false);
if(cb_thickness3->isChecked())
cb_thickness3->setChecked(false);
}
void MainWind::cb_thickness3_isChecked()
{
if(cb_thickness1->isChecked())
cb_thickness1->setChecked(false);
if(cb_thickness2->isChecked())
cb_thickness2->setChecked(false);
}
Code doesn't work as expected. When I click to any ChBx first time, everything is OK, but when I click to other next time it only uncheck previous and does nothing with itself. Only on second click it become chekced.
Also I found one more bug, when I check to ChBox, and then uncheck it by clicking it againg, I can check 2 ChBxes. [pic 2]
Radio button is a great idea.
But if you really want to use check box, you can explicitly set cb_thickness1 checked in cb_thickness1_isChecked(), and do the same for other two check boxes.
void MainWind::cb_thickness1_isChecked()
{
cb_thickness1->setChecked(true);
cb_thickness2->setChecked(false);
cb_thickness3->setChecked(false);
}
void MainWind::cb_thickness2_isChecked()
{
cb_thickness1->setChecked(false);
cb_thickness2->setChecked(true);
cb_thickness3->setChecked(false);
}
void MainWind::cb_thickness3_isChecked()
{
cb_thickness1->setChecked(false);
cb_thickness2->setChecked(false);
cb_thickness3->setChecked(true);
}
I suggest to derive a class from QCheckBox (lets call it CustomCheckBox) and add a signal, private slot and public slot
signal:
void enabled();
private slot:
void CustomCheckBox::checkEnable(bool state)
{
if(state)
{
emit enabled();
}
}
public slot:
void CustomCheckBox::uncheck()
{
setChecked(false);
}
In the constructor add:
connect(this,SIGNAL(toggled(bool)),this,SLOT(checkEnable(bool)));
This way you can use simple connects.
CustomCheckBox *box1 = new CustomCheckBox();
CustomCheckBox *box2 = new CustomCheckBox();
connect(box1,SIGNAL(enabled()),box2,SLOT(uncheck()));
Feel free to improve this answer. :)
Verify that the state of the button is checked in the slot and then deactivate the other checkboxes like you already did. You can use the parameter of the stateChanged method by passing it to the slots.
Here is code that works:
Variant I:
connect(ui->checkBoxA, SIGNAL(stateChanged(int)), this, SLOT(checkBoxAChanged(int)));
connect(ui->checkBoxB, SIGNAL(stateChanged(int)), this, SLOT(checkBoxBChanged(int)));
connect(ui->checkBoxC, SIGNAL(stateChanged(int)), this, SLOT(checkBoxCChanged(int)));
void MainWindow::checkBoxAChanged(int state)
{
if (state == Qt::Checked) {
ui->checkBoxB->setChecked(false);
ui->checkBoxC->setChecked(false);
}
}
void MainWindow::checkBoxBChanged(int state)
{
if (state == Qt::Checked) {
ui->checkBoxA->setChecked(false);
ui->checkBoxC->setChecked(false);
}
}
void MainWindow::checkBoxCChanged(int state)
{
if (state == Qt::Checked) {
ui->checkBoxB->setChecked(false);
ui->checkBoxA->setChecked(false);
}
}
Variant II:
connect(ui->checkBoxA, SIGNAL(clicked(bool)), this, SLOT(checkBoxAClicked(bool)));
connect(ui->checkBoxB, SIGNAL(clicked(bool)), this, SLOT(checkBoxBClicked(bool)));
connect(ui->checkBoxC, SIGNAL(clicked(bool)), this, SLOT(checkBoxCClicked(bool)));
void MainWindow::checkBoxAClicked(bool val)
{
if (val == true) {
ui->checkBoxB->setChecked(false);
ui->checkBoxC->setChecked(false);
}
}
void MainWindow::checkBoxBClicked(bool val)
{
if (val == true) {
ui->checkBoxA->setChecked(false);
ui->checkBoxC->setChecked(false);
}
}
void MainWindow::checkBoxCClicked(bool val)
{
if (val == true) {
ui->checkBoxB->setChecked(false);
ui->checkBoxA->setChecked(false);
}
}

wxWidgets Accessing TopFrame of Another Process

I have an application which has the parent frame as the MainFrame and two child frames, ChildA and ChildB. This should be a document oriented GUI such that when user clicks a document, it should be able to open another instance of FrameA.
When I click the executable of GUI MainFrame, ChildA and ChildB loads normally. However when the executable is running and when I click a document I realized that Windows is opening it as another process such that MainFrame, ChildA and ChildB loads again which I dont want cause I only want to open another instance of ChildA to show the contents of the document.
My code is as follows:
bool MainFrameApp::OnInit()
{
m_AnotherInstanceRunning=false;
m_checker = new wxSingleInstanceChecker;
if(m_checker->IsAnotherRunning()) m_AnotherInstanceRunning=true;
//Some other code
if(!m_AnotherInstanceRunning)
{
frame= new MainFrame(0L);
std::cout<<"Frame:"<<frame; //Prints the address
auto m_ChildA=new SomeChildFrame(frame);
frame->Show();
m_FrameA->Show(true);
wxTheApp->SetTopWindow(frame);
}
if(m_AnotherInstanceRunning)
{
frame=dynamic_cast<MainFrame*>(wxTheApp->GetTopWindow());
std::cout<<"Frame:"<<frame; //prints 0
frame->OpenDocument(frame,strDocDirectory,strDocName); //Does not work
return false;
}
My question is, when I click on a document how can I open that document within an already running MainFrame.
EDIT 1:
This is how I achieved it after countless of hours...
Below is the code for MainFrame.h
const int SERVER_ID=wxNewId();
const int SERVERSOCKET_ID=wxNewId();
const int CLIENTSOCKET_ID=wxNewId();
class MainFrame;
class MainFrameApp : public wxApp
{
bool m_AnotherInstanceRunning;
wxSocketServer* m_server;
wxString m_DocDirectoryPath;
wxString m_DocFullName; //including extension
protected:
virtual void OnServerEvent(wxSocketEvent& event);
virtual void OnServerSocketEvent(wxSocketEvent& event);
virtual void OnClientSocketEvent(wxSocketEvent& event);
public:
MainFrame* m_MainFrame;
wxSingleInstanceChecker* m_checker;
};
static const wxCmdLineEntryDesc cmdLineDesc[] =
{
{wxCMD_LINE_PARAM, NULL, NULL, "", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE},
{wxCMD_LINE_NONE},
};
Below is the code for MainFrame.cpp
bool ScienceSuitApp::OnInit()
{
m_AnotherInstanceRunning=false;
m_checker = new wxSingleInstanceChecker;
if(m_checker->IsAnotherRunning()) m_AnotherInstanceRunning=true;
wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
glbStrExeDir=exePath.GetPath()+wxFileName::GetPathSeparator();
wxString strDocFullPath; //This is directory+name
if(argc>1)
{
wxCmdLineParser parser(cmdLineDesc, argc, argv);
parser.Parse();
strDocFullPath=argv[1];
wxFileName docPath(strDocFullPath);
m_DocDirectoryPath=docPath.GetPath()+wxFileName::GetPathSeparator();
m_DocFullName=docPath.GetFullName(); //we needed extension of document as well
}
if(!m_AnotherInstanceRunning)
{
//Some other code
//Here Process #1
m_MainFrame= new MainFrame(0L);
m_MainFrame->Show();
wxIPV4address addr;
addr.Service(3000);
m_server = new wxSocketServer(addr,wxSOCKET_WAITALL);
if (!m_server->Ok())
{
if (m_server->LastError() == wxSOCKET_INVPORT) wxMessageBox(wxT("Port in use!"));
m_server->Destroy();
}
m_server->SetEventHandler(*this, SERVER_ID);
m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
m_server->Notify(true);
Connect(SERVER_ID,wxID_ANY, wxEVT_SOCKET,wxSocketEventHandler(MainFrameApp::OnServerEvent));
Connect(SERVERSOCKET_ID,wxID_ANY,wxEVT_SOCKET,wxSocketEventHandler(MainFrameApp::OnServerSocketEvent));
}
if(m_AnotherInstanceRunning)
{
//Here is for Process #2
Connect(CLIENTSOCKET_ID,wxID_ANY,wxEVT_SOCKET,wxSocketEventHandler(MainFrameApp::OnClientSocketEvent));
wxIPV4address addr;
addr.Hostname(wxT("localhost"));
addr.Service(3000);
wxSocketClient* Socket = new wxSocketClient();
Socket->SetEventHandler(*this, CLIENTSOCKET_ID);
Socket->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
Socket->Notify(true);
if(!Socket->Connect(addr, true)) wxMessageBox("Failed to connect to server");
return true;
}
return true;
}
void MainFrameApp::OnServerEvent(wxSocketEvent& event) //Process #1
{
wxSocketBase* sock = m_server->Accept(false);
sock->SetEventHandler(*this, SERVERSOCKET_ID);
sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
sock->Notify(true);
}
void MainFrameApp::OnServerSocketEvent(wxSocketEvent& event) //Process #1
{
wxSocketBase *sock = event.GetSocket();
wxCharBuffer buf(256);
switch(event.GetSocketEvent())
{
case wxSOCKET_CONNECTION:
{
break;
}
case wxSOCKET_INPUT:
{
sock->Read(buf.data(), 255);
wxString pathstr=wxString::FromUTF8(buf);
sock->Destroy();
wxFileName docPath(pathstr);
wxString DocDirectoryPath=docPath.GetPath()+wxFileName::GetPathSeparator();
wxString DocFullName=docPath.GetFullName(); //we needed extension of document as well
m_MainFrame->OpenDocument(m_MainFrame,DocDirectoryPath,DocFullName);
break;
}
case wxSOCKET_LOST:
{
sock->Destroy();
break;
}
}
}
void MainFrameApp::OnClientSocketEvent(wxSocketEvent& event) //Process #2
{
wxString str=m_DocDirectoryPath+m_DocFullName;
wxSocketBase* sock = event.GetSocket();
switch(event.GetSocketEvent())
{
case wxSOCKET_CONNECTION:
{
sock->Write(str.mb_str(),str.length());
}
}
//Exit the client process (Process #2) staying in the background, otherwise and no messages are sent
//Also we dont want to spawn background processes
exit(0);
}
If you want to prevent more than one instance of your application running at the same time, you can use wxSingleInstanceChecker to check if another one is running and use the IPC classes to send the name of the document to open to the other instance if it is.

Glass - Slow camera \ FileObserver notification - XE12 - using ACTION_IMAGE_CAPTURE

I have basically implemented the new XE12\GDK2 cameramanager sample code to capture an image on application start. However, the notification to the FileObserver callback takes anywhere from 3 to 30 seconds to get the notification of the image file creation. Taking a picture using the default 'Take a Picture' app works just fine so I dont thin it is an OS\update issue.
My app's behavior is like:
- Take the picture
- Tap to accept
Wait 3 to 30 seconds
- Get the callback and the imageview is updated with the captured image.
I dont think I have modified a single line of the sample code provided in the GDK 2.0 camera tutorial. So wondering what I am missing.
I have attached the relevant section of the code below. Any tips\pointers highly appreciated.
#Override
protected void onStart() {
super.onStart();
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// String path = Environment.getExternalStorageDirectory().getPath();
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
private void processPictureWhenReady(final String picturePath) {
final File pictureFile = new File(picturePath);
if (pictureFile.exists()) {
// The picture is ready; process it. Takes 3-30 seconds to get here!
try {
Bitmap imageBitmap = BitmapFactory.decodeFile(picturePath);
int w = imageBitmap.getWidth();
int h = imageBitmap.getHeight();
Bitmap bm2 = Bitmap.createScaledBitmap(imageBitmap, w/2, h/2, true);
imageBitmap = bm2.copy(bm2.getConfig(), true);
//m_ImageView.setImageBitmap(bm2);
} catch (Exception e) {
Log.e("Exc", e.getMessage());
}
} else {
tm = System.currentTimeMillis();
// The file does not exist yet. Before starting the file observer, you
// can update your UI to let the user know that the application is
// waiting for the picture (for example, by displaying the thumbnail
// image and a progress indicator).
final File parentDirectory = pictureFile.getParentFile();
FileObserver observer = new FileObserver(parentDirectory.getPath()) {
// Protect against additional pending events after CLOSE_WRITE is
// handled.
private boolean isFileWritten;
#Override
public void onEvent(int event, String path) {
if (!isFileWritten) {
// For safety, make sure that the file that was created in
// the directory is actually the one that we're expecting.
File affectedFile = new File(parentDirectory, path);
isFileWritten = (event == FileObserver.CLOSE_WRITE
&& affectedFile.equals(pictureFile));
if (isFileWritten) {
stopWatching();
// Now that the file is ready, recursively call
// processPictureWhenReady again (on the UI thread).
runOnUiThread(new Runnable() {
#Override
public void run() {
processPictureWhenReady(picturePath);
}
});
}
}
}
};
observer.startWatching();
}
}
Answering my own question - though I got the clarifications from Jenny Murphy and John Feig :-). Hopefully it helps others.
To the first point - why is image capture using the sample code from the GDK guide so slow:
This is the expected behavior. The Glass camera intent (ACTION_IMAGE_CAPTURE) performs a ton of proprietary post-processing on the captured image - auto-HDR etc which takes time. This is cleverly disguised in the 'Take a picture' command by only displaying the preview image (which is available immediately.). As proof, try to find the image you just took in your time-line. You will not see it for several seconds (around 8 seconds on average in my experience.).
Frankly, unless you are ok just grabbing the preview image, the camera intent may not be very useful in most apps.
The solution is to use the Camera directly using default Android APIs. For convenience, I have pasted a snippet of this code. Please excuse if it is kind of basic for many of you. A lot of the code is copied from John Feig's GIFCamera glassware on GitHub
activity_main layout contains a SurfaceView called preview
<SurfaceView
android:id="#+id/preview"
android:layout_width="500dp"
android:layout_height="500dp"
android:layout_alignParentTop="true"
android:layout_marginTop="20dp"
/>
MainActivity.java
public class MainActivity extends Activity implements PhotoCallback {
public byte[] m_jpg = null;
Camera cam = null;
SurfaceHolder m_sh;
private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder hldr) {
m_sh = hldr;
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
myCapHandler2(); //Start Camera Preview etc.
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SurfaceView preview = (SurfaceView) findViewById(R.id.preview);
preview.getHolder().addCallback(mSurfaceHolderCallback);
}
public void myCapHandler2() {
//open camera
try {
cam = Camera.open(0);
Camera.Parameters params = cam.getParameters();
List<Size> sizes = params.getSupportedPreviewSizes();
params.setJpegQuality(90);
params.setPreviewFpsRange(30000, 30000);
params.setPictureSize(sizes.get(1).width, sizes.get(1).height);
params.setPreviewSize(sizes.get(1).width, sizes.get(1).height);
cam.setParameters(params);
try {
cam.setPreviewDisplay(m_sh);
}
catch (IOException e) {
e.printStackTrace();
}
// Important: Call startPreview() to start updating the preview
// surface. Preview must be started before you can take a picture.
cam.startPreview();
cam.takePicture(null, null,
new PhotoHandler(this));
} catch (Exception e) {
if (null != cam) {
cam.stopPreview();
cam.release();
}
}
}
#Override
public void pictureTaken(byte[] jpg) {
m_jpg = jpg;
//Picture captured - release the camera for other apps
cam.stopPreview();
cam.release();
}
#Override
public void onPause() {
if (null != cam) {
cam.stopPreview();
cam.release();
}
}
#Override
public void onDestroy() {
if (null != cam) {
cam.stopPreview();
cam.release();
}
}
}
PhotoHandler.java
import android.hardware.Camera;
import android.os.AsyncTask;
public class PhotoHandler implements Camera.PictureCallback {
private PhotoCallback photoCallback;
public PhotoHandler(PhotoCallback photoCallback) {
super();
this.photoCallback = photoCallback;
}
#Override
public void onPictureTaken(byte[] data, Camera camera) {
new ProcessCapturedImage().execute(data);
}
private class ProcessCapturedImage extends AsyncTask<byte[], Void, byte[]> {
#Override
protected byte[] doInBackground(byte[]... params) {
if (null == params || null == params[0])
return null;
return params[0];
}
#Override
protected void onPostExecute(byte[] params) {
photoCallback.pictureTaken(params);
}
}
}
PhotoCallback.java
public interface PhotoCallback {
public void pictureTaken(byte[] jpg);
}
All the best with your camera glassware.

Repaining listfield on editfield change Input

I am using Google place API in my application for searching location. When user input text in edit field then the API called and resulted output will shown in a list.
I implemented it successfully but the problem is that each time edit field text changes, the list is not repainting and output is added to the end of the list. I want every time the text changes in the edit text field, the list must remove its previous content that are invalid.
This can be seen in pictures:
For Implementing this, I have written this code:
public final class MyScreen extends MainScreen {
/**
* Creates a new MyScreen object
*/
private Vector _listElements;
ListField list;
JSONObject[] jsonobject;
EditField editfield;
String url = "https://maps.googleapis.com/maps/api/place/autocomplete/json?input=";
String[] locationName;
VerticalFieldManager verticalFieldManager = new VerticalFieldManager();
public MyScreen() {
ButtonField search = new ButtonField("Search");
_listElements = new Vector();
list = new ListField();
ListCallback _callback = new ListCallback(this);
// Set the displayed title of the screen
setTitle("Search Edit Field");
editfield = new EditField();
editfield.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
list.invalidate();
createField();
}
});
}
});
list.setCallback(_callback);
add(editfield);
add(new SeparatorField());
verticalFieldManager.add(list);
add(verticalFieldManager);
}
protected void createField() {
ShowList();
reloadList();
}
private void reloadList() {
list.setSize(_listElements.size());
}
class ListCallback implements ListFieldCallback {
MyScreen listDemoScreen;
public ListCallback(MyScreen listDemoScreen) {
this.listDemoScreen = listDemoScreen;
}
public void drawListRow(ListField list, Graphics g, int index, int y,
int w) {
String text = (String) _listElements.elementAt(index);
list.setRowHeight(getFont().getHeight());
g.drawText(text, 0, y, 0, -1);
}
public Object get(ListField list, int index) {
return _listElements.elementAt(index);
}
public int indexOfList(ListField list, String prefix, int string) {
return _listElements.indexOf(prefix, string);
}
public int getPreferredWidth(ListField list) {
return Display.getWidth();
}
}
protected void ShowList() {
HttpConnection httpConn;
InputStream in;
ConnectionFactory connFact = new ConnectionFactory();
ConnectionDescriptor connDesc;
String response;
String fieldText = editfield.getText();
connDesc = connFact.getConnection(url + fieldText
+ "%#&sensor=true&key=xxxxxxxxxxxxx"
+ ConnectionType.getConnectionType());
if (connDesc != null) {
httpConn = (HttpConnection) connDesc.getConnection();
try {
int responseCode = httpConn.getResponseCode();
if (responseCode == HttpConnection.HTTP_OK) {
in = httpConn.openInputStream();
StringBuffer buf = new StringBuffer();
int read = -1;
while ((read = in.read()) != -1)
buf.append((char) read);
response = buf.toString();
try {
JSONObject object = new JSONObject(response);
JSONArray ar = object.getJSONArray("predictions");
jsonobject = new JSONObject[ar.length()];
locationName = new String[ar.length()];
list.invalidate();
for (int i = 0; i < ar.length(); i++) {
jsonobject[i] = ar.getJSONObject(i);
_listElements.addElement(jsonobject[i]
.getString("description"));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
} else {
Dialog.alert("Connection not succeded");
}
}
protected boolean onSavePrompt() {
return true;
}
}
Update and Solution:
only modify this and this rest is working fine. As Peter Suggests, we can also put a Thread.sleep(time); in order to get the UI not blocked:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
_listElements.removeAllElements();
createField();
}
});
I think your problem is simply that you do not clear the _listElements Vector when you request more data. So _listElements just gets bigger.
However there is a bigger problem here and that is that your code appears to be running networking operations on the Event Thread. What your should do in your changeListener. is start a Thread that requests the data, then repopulate the ListField when this tread gets data.
As a result of this change, the UI will not be blocked, and the List updates will become asynchronous, so your user could in fact enter another character into the EditField before the first Thread response comes back. To prevent this looking silly, you could delay the Thread processing for a fraction of second to see if another character is entered, and/or you could make sure that the EditField content was still the same as the requested characters before you repopulate it.
I personally prefer this asynchronous approach, but if it bothers you, you could put a 'please wait - loading' type screen to block the user until the response comes back.
Update
Remember that if you start a background Thread, you need to get back onto the Event Thread to do Ui Processing. Typically this is done simply by including your UI code within the run method of a Runnable that is invoked later, for example:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
// Ui Code in here
}
});
You should only put Ui Updating code in the runnable. Networking processing, or any other blocking action, should NOT be included.

Rhino Mocks, MbUnit: Best way to check if object has raised an event

I have an object that I'm testing that raises an event. What is the best way of using Rhino Mocks to check that it was raised?
Best I could come up with (I am certain it gets better than this):
public void MyCallback(object sender, EventArgs e) { _flag = true;}
[Test]
public void DoSomethingRaisesEvent() {
_flag = false;
using(_mocks.Record()) {
Expect.Call(delegeate { _obj.DoSomething();});
}
using(_mocks.Playback()) {
_obj = new SomethingDoer();
_obj.SomethingWasDoneEvent += new EventHandler(MyHandler);
Assert.IsTrue(_flag);
}
}
I found this article by Phil Haack on how to test events using anonymous delegates
Here is the code, ripped directly from his blog for those too lazy to click through:
[Test]
public void SettingValueRaisesEvent()
{
bool eventRaised = false;
Parameter param = new Parameter("num", "int", "1");
param.ValueChanged +=
delegate(object sender, ValueChangedEventArgs e)
{
Assert.AreEqual("42", e.NewValue);
Assert.AreEqual("1", e.OldValue);
Assert.AreEqual("num", e.ParameterName);
eventRaised = true;
};
param.Value = "42"; //should fire event.
Assert.IsTrue(eventRaised, "Event was not raised");
}
I'm not sure how your test actually calls the DoSomething() Method. Maybe you're missing something to fire the event. Other than that, I think you have are on the right track for testing events with Rhino Mocks
In any case, here is another way I like to deal with events:
[Test]
public void MyEventTest()
{
IEventRaiser eventRaiser;
mockView = _mocks.CreateMock<IView>();
using (_mocks.Record())
{
mockView.DoSomethingEvent += null;
eventRaiser = LastCall.IgnoreArguments();
}
using (_mocks.Playback())
{
new Controller(mockView, mockModel);
eventRaiser.Raise(mockView, EventArgs.Empty);
}
}