locked
Why does CameraCaptureUI.captureFileAsync fail to return IAsyncOperation object?

    Question

  • For some reason, my code is unable to retrieve the IAsyncOperation object that is returned upon calling captureFileAsync method of the Windows.Media.Capture.CameraCaptureUI() method. The IAsyncOperation object is returned according to it's documentation. In that documentation it states:

    Return value Type: IAsyncOperation<StorageFile> When this operationcompletes, a StorageFile object is returned.

    So here is my code:

    var dialog = new Windows.Media.Capture.CameraCaptureUI();
    var aspectRatio = { width: 4, height: 3 };
    
    dialog.photoSettings.croppedAspectRatio = aspectRatio;
    appSession.InAsyncMode = dialog.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo).done(function (file) {
            if (file) {
                self.addPage(URL.createObjectURL(file));
            } else {
                WinJS.log && WinJS.log("No photo captured.", "sample", "status");
            }
        }, function (err) {
                // None taken
        });

    When I inspect the value of appSession.InAysncMode, I see that the function returns undefined. I suspect it returns undefined because the operation is not complete (i.e. the user has not yet created the photo, and it has not been saved to disc), but I need it in order to cancel out of the camera capture mode programmatically. Does anybody know why it would return undefined instead of the documented IAsyncOperation object?

    To put it succintly, is there a way to programatically cancel out of the Camera Capture UI screen?  That is, when the camera is active, is there code that can cancel out of it?

    Thanks!  

    If you didn't read my post above, another way to ask the question is:  is there a way to programatically cancel out of the camera capture UI?
    If you didn't read my post above, another way to ask the question is:  is there a way to programatically cancel out of the camera capture UI?
    Monday, September 9, 2013 4:21 PM

All replies

  • To answer your ending question, you can cancel the capture UI by canceling the promise from dialog.captureFileAsync.

    Your InAsyncMode flag is undefined because you're assigning to it the return value from captureFileAsync.done() which is, by definition, undefined. It has nothing to do with the API's success.

    In the docs, when you see IAsyncOperation<type>, what you get in JavaScript is a promise that will deliver <type> as a result to the completed handler if it succeed. You never see IAsyncOperation or related interfaces in JavaScript directly. The documentation for WinRT is written to be language-neutral, so it's important to understand how those things show up in JS (as promises). In C# you don't see it either, as you just use the await keyword. It's mostly in C++ that you actually encounter the interface.

    Anyway, you I believe you want is something along the lines of the code below, where you could eliminate IsAsyncMode in favor of just checking for a non-null promise:

    appSession.capturePromise = dialog.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo); appSession.IsAsyncMode = (appSession.capturePromise != null);

    //This will close the capture UI after 5 seconds--replace with whatever logic you need
    setTimeout(function () { appSession.capturePromise.cancel(); }, 5000); appSession.capturePromise.done(function (file) { if (file) { } else { } }, function (err) { appSession.IsAsyncMode = false;
    appSession.capturePromise = null; });

    Kraig

    Author, Programming Windows 8 Apps with HTML, CSS, and JavaScript, a free ebook from Microsoft Press

    Also see second edition preview (lots on promises in there)



    Monday, September 9, 2013 5:16 PM
  • Thanks Kraig!  Your time and expertise is greatly appreciated.  I'll check that out today to see if you suggestions work.

    Please note, as the author of `Programming Windows 8 Apps with HTML, CSS, and Javascript`, it might be a good idea to help out on StackOverflow since many devs who use HTML / CSS / and Javascript use that forum as a learning resource.  I posted this question there a a week ago from today, and did not get any answers, nor did I get any comments.  It wasn't until I posted on MSDN that I received an answer from you--the guy who "wrote the book" on this stuff.  That tells me something is wrong with getting folks on board to code Win 8 apps with WinJS.  If Microsoft's idea is to get web devs on board to create apps for their platform, there's got to be more tech evangalism outside of MSDN.  

    Anyways, thanks again for your answer.  It definitely helps.  I'll come back and update whether or not it worked.

    Tuesday, September 10, 2013 2:06 PM
  • Thanks for the suggestion. I do watch StackOverflow some, but not as carefully as MSDN. I do notice that problems show up on both and out of habit, I think, I tend to answer on MSDN first. But I do want to increase my presence on SO, so thanks for the encouragement.

    BTW, did you post this answer on SO as well?

    Tuesday, September 10, 2013 2:41 PM
  • I have not answered on SO.  Please feel free to do so in order to gain points there as well.  I can put a link to here, though.

    The good news is that your suggestion allows me to cancel out of the async mode, but I am still left with the problem I faced before I could implement that.  

    My application has a class that is shared by all screens within the app, and I'm instantiating that class into a global variable called appSession.  This class keeps track of user activity, and if no activity is detected, it logs out the user, displays a Windows.UI.Popups.MessageDialog, and automatically navigates the user back to the login screen.  I have to handle this in the Camera Capture mode, and this solution allows me to cancel out of the Camera Capture mode programatically, but when the MessageDialog.showAsync() method is called it throws the "Access is Denied" error.  I thought that if I canceled out of the Camera Capture UI, I would be able to call the .showAsync() method of the MessageDialog object.  Why is it the case that I cannot do that?

    Tuesday, September 10, 2013 3:43 PM
  • Can you show me the code sequence that you're using there? My suspicious is that you might need to yield (e.g. setImmediate) off the UI thread before invoking the MessageDialog.

    As a design suggestion, you could consider not using the MessageDialog in the first place--doesn't the reappearance of the login screen suffice to alert the user that their session has ended? Seems like the MessageDialog is superfluous, especially because you're showing it specifically in the case of no user activity, which means a user really isn't there to see it in the first place. Just a thought. :)

    Thursday, September 12, 2013 3:40 PM