MediaCapture and Window VisibilityChanged - windows-runtime

[Question]
On Windows Phone 8.1, what exactly happens in between the time when the user leaves the app and the OnSuspended event fires? I'm having trouble with the ability to manage objects in that span, in particular MediaCpture object.
To better explain the problem, here is the scenario:
The user is on a page with a video preview being pumped to a CaptureElement
The user taps the Start button
The user taps Back button and returns to the page with a broken MediaCapture
With WinRT there isn't an ObscuredEvent and OnNavigatingFrom doesn’t fire unless you’re going to another page in the same Frame. After some investigation, I've found that the only event that fires is Window.Current.VisibilityChanged
I've gone ahead and hook it when the page is NavigatedTo and unhooked in OnNavigatedFrom (see ex2 below). Inside the event, I check for parameter that tells if the app is hiding or showing and dispose/initialize accordingly(see ex.1 below).
[Problem]
However, this only works with the debugger attached. If I do this without the debugger attached, it doesn't reinitialize and frequently crashes the camera and I have to literally reboot the device.
Code Example 1 (note: e.Visible == false is leaving the app and true when returning)
async void Current_VisibilityChanged(object sender, VisibilityChangedEventArgs e)
{
if (!e.Visible) //means leaving the app
{
await DisposeAll(); //cleans the MediaCapture and CaptureElement
}
else
{
if(mediaCaptureManager != null) await DisposeAll();
await Initialization(); //set up camera again
}
}
Example 2 (hooking into the event)
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Window.Current.VisibilityChanged += Current_VisibilityChanged;
this.navigationHelper.OnNavigatedTo(e);
}
protected async override void OnNavigatedFrom(NavigationEventArgs e)
{
Window.Current.VisibilityChanged -= Current_VisibilityChanged;
this.navigationHelper.OnNavigatedFrom(e);
}
[Update: Resolution]
Instead of using VisibilityChanged, hook into Window.Current.Activated on the page's constructor. With the debugger completely detached, the Activated event will provide the WindowActivationState parameter in the WindowActivatedEventArgs. Like this:
private async void CurrentOnActivated(object sender, WindowActivatedEventArgs e)
{
if(e.WindowActivationState == CoreWindowActivationState.Deactivated)
{
//dispose MediaCapture here
}
else if(e.WindowActivationState == CoreWindowActivationState.CodeActivated || e.WindowActivationState == CoreWindowActivationState.PointerActivated)
{
//initialize MediaCapture here
}
}

See my answer in https://stackoverflow.com/a/28592882/3998132. Using Window.VisibilityChanged in conjunction with your Page\UserControl Loaded\Unloaded handler should solve your issue I believe.
Using Window.Activated is less desirable than Window.VisibilityChanged because Activated relates to being visible AND having focus where as VisibilityChanged only pertains to visibility. For showing a preview having focus is not applicable. Since Windows Store apps on Windows Phone can only have one Window showing there is no difference in using either however if your app becomes universal and runs on let's say on Windows 8+ Modern shell (which can show multiple Store apps with the Snap window feature) or Windows 10 desktop (which can support multiple Store apps showing at the same time) you will not want to stop preview when a user changes focus from your app but your app is still showing.

I'm not sure if it wouldn't be more suitable to use Suspending/Resuming events. Note only that in this case, you will have to debug it properly - it behaves little different while being run with/without debugger attached.
As for the code - hooking your event in OnNavigatedTo/OnNavigatedFrom is not a good idea - when the OS suspends the app and you are using SuspensionManager then OnNavigatedFrom will be called, but when you go back to your app (resume it), then OnNavigatedTo will not be called.
Using Window events may also work here, but why not subscribe it once, somewhere in constructor? - it's window-wide and hence in phone there is only one window, which stands for app, then subscribe once. In this case, you may add a line that recognizes the current page in window and if that page contains mediacapture then dispose (create similar). Then you can also dispose/initialize in navigation events in case user doesn't leave your app and just navigate.

Related

Soundeffect not playing in background

I have an application that allows the user to take photos and save to isolated storage for upload to a server.
I am trying to play a shutter sound when the user clicks the software capture button provided. All documentation I can find indicates that soundeffect.play is asynchronous so the sound should keep playing in the background while logic continues, however in my case the sound either only partially plays or does not have time to play unless I put a breakpoint just after play() or add a Thread.Sleep(x) just after the call to play().
private void BtnCaptureClick(object Sender, RoutedEventArgs E)
{
if (_PhotoCamera != null)
{
PlayShutter();
_FileName = Guid.NewGuid().ToString(); //A breakpoint here will allow sound to play
_PhotoCamera.CaptureImage();
}
}
private void PlayShutter()
{
var Info = App.GetResourceStream(new Uri("Assets/camera.wav", UriKind.Relative));
try
{
_Effect = SoundEffect.FromStream((Info.Stream));
FrameworkDispatcher.Update();
using (_Effect)
{
if (_Effect.Play())
{
//Thread.Sleep(1000); //uncommenting this will allow sound to play if duration < 1000
}
}
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message);
}
}
I have tried using a soundeffectinstance explicitly, however behaviour does not change.
I have tried explicitly calling Play() asynchronously, no change in behaviour.
I have tried calling the following code asynchronously, no change in behaviour.
I have tried calling FrameworkDispatcher.Update frequently, no change in behaviour.
I have tried setting the .wav file in the project to “Resource” but this causes a nullreferenceexception when I call _Effect = SoundEffect.FromStream((Info.Stream)); because Info is null.(even with an absolute path)
This behaviour is present using both the emulator and an actual device via usb connection to pc to debug.
Can anybody help me resolve this frustrating issue please?
Answering my own issue now, it was the using block causing this behaviour, as the instance was being disposed. No idea why I was using that!

Showing m.bing.com in the WP8 WebBrowser control

I'm having a problem getting bing.com to load in a WebBrowser control on Windows Phone 8. It seems that doing that will launch the WP8 Search App (same as pressing the Search button on the phone). The problem is, once you click a result in that search app, it doesn't take you back to your original app - it goes to IE to show the result. This isn't going to work for me and seems to be a massive flaw (IMO) in the WebBrowser behavior.
There does seem to be a few apps out there that have succeeded in being able to show bing.com without launching the phone's search app - for example Image Downloader Free. There was another one, but I can't remember what it was...
After some research, I've found that the WebBrowser_Navigating event gets fired 3 times when going to bing.com: first request to the user-entered URL (www.bing.com), it then gets redirected to http://wp.m.bing.com/?mid=10006, then it redirects to bing://home/?mid=10006.
Preventing it from forwarding to the Bing search app is quite simple, just add this to the Navigating event:
e.Cancel = (e.Uri.Scheme == "bing");
The problem is, it then only shows the Bing search page place holder which says "Bing Search" and has a link that says "Back to Bing search" which does nothing (it would typically relaunch the Bing Search app).
I have a few thoughts, but I'm not sure how feasible they are.
In the WP8 WebBrowser control, is it possible to fake the User Agent?
Can one of the items in the WebBrowser.Uri.Flags property be removed or added to affect the way Bing.com handles the request?
If none of those work, I can simply create a dummy page on my web server, redirect all bing.com requests to it, and have it grab the m.bing.com front page with a card-coded user-agent. I really would like to avoid having to do this option though. From an End-User perspective, they would never know, but I just added a whole new layer of overhead, maintenance and resource-wise.
If you're interested, attached are the diff's for the EventArgs object between the 3 requests that occur in the WebBrowser.Navigating event:
Request 1 (bing.com) -> Request 2 (forwarded to wp.m.bing.com/?mid=10006)
Request 2 (forwarded to wp.m.bing.com/?mid=10006) -> Request 3 (forwarded to bing://home/?mid=10006)
tl;dr Does anyone know of a way to prevent www.bing.com from causing the search app to launch in the WebBrowser control in my application?
Thank you!
I don't know if there's a better way to handle this, but I found a solution. I haven't gotten it to work perfectly when the back button is clicked, so I will update my answer if/when I found a more solid solution. I still think this is a big flaw in the WebBrowser control in WP8.
Here is the code:
private bool _customHeaderRequest = false;
private void MainBrowser_Navigating(object sender, NavigatingEventArgs e)
{
string host = e.Uri.Host.ToLowerInvariant().Trim();
if ((host == "bing.com" || host.EndsWith(".bing.com")) && !_customHeaderRequest)
{
e.Cancel = true;
Dispatcher.BeginInvoke(() =>
MainBrowser.Navigate(e.Uri, null,
"User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 710)\r\n"));
_customHeaderRequest = true;
return;
}
_customHeaderRequest = false;
}
private void MainBrowser_Navigated(object sender, NavigationEventArgs e)
{
_customHeaderRequest = false;
}
I don't have access to my emulator, but I tried it on my phone, and:
The redirect doesn't happen when you "Prefer desktop version" and open m.bing.com. Warning: The mobile version isn't very pretty.
Try disabling scripts on your WebBrowser, that could stop the redirect from happening.
Any chance you could just use Google?

Swing JTabbedPane : addChangeListener or addContainerListener or both?

I have one swing code written by other person. For swing tabbed pane, he has added both change and container listener and both calls the same method:
addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent theEvent ) {
someMethod();
}
} );
addContainerListener(new ContainerAdapter() {
public void componentAdded(ContainerEvent theEvent) {
someMethod();
}
public void componentRemoved(ContainerEvent theEvent) {
someMethod();
}
} );
Whenever tab is removed from this tabbed pane, it internally calls JTabbedPane.removeTabAt(int index), which in turn calls fireStateChanged() causing new change event listened by change listener.
Now as new component (tab) is removed from tabbed pane, it also calls componentRemoved(ContainerEvent theEvent) method of container listener.
Both change even and container events, then calls same method someMethod(), which does set background and foreground colors.
I would like to know, if this kind code might cause some issues. Recently we are facing random IndexOutOfBoundException exeptions. I am just wondering, if this is causing this issue.
Also as per my understanding in swing, once event is listened, logic inside it should be executed using worker thread (e.g. SwingWorker). Please let me know if this is correct.
I am new to swing, thus any hint would be appreciated.
Thanks.
Whenever tab is removed from this tabbed pane, it internally calls
JTabbedPane.removeTabAt(int index), which in turn calls
fireStateChanged() causing new change event listened by change
listener.
This is true if the removed tab is also the selected tab. In the other cases, you won't be notified.
You need to choose what event you want to listen to:
Addition/Removal of components?--> go for ContainerListener
Selected tab? --> go for ChangeListener
I would like to know, if this kind code might cause some issues.
Recently we are facing random IndexOutOfBoundException exeptions. I am
just wondering, if this is causing this issue.
Since there is no line in your sample code that could throw that Exception, it is impossible to answer your question. Post an SSCCE that shows your issue.
Also as per my understanding in swing, once event is listened, logic
inside it should be executed using worker thread (e.g. SwingWorker).
Please let me know if this is correct.
It depends:
If you need to modify anything in the UI, anything related to Swing, it needs to be executed on the EDT (Event Dispatching Thread) and thus, SwingWorker is not an option.
If you need to perform business logic operations, and especially if they can be lengthy, then you should indeed use a SwingWorker or any other mechanism to execute that code in another thread than the EDT. Consider visiting the Swing tag wiki on "Concurrency"

Windows Store app button respond to click but event is not fired successfully

I go this response in Certification report:
The app does not appear to fully support touch input. The various
tiles on the main screen respond to touch/clicks but do not launch an
action. Touch support in this app do not appear to work to our
reviewers. Please see:
http://msdn.microsoft.com/en-us/library/windows/apps/Hh761498.aspx for
some of the common interactions for keyboard, mouse and touch.
This has never been an issue while developing and testing on several desktop computers and Surface RT. Any ideas on what might be the cause, or how I might reproduce it? The actions mentioned are hooked up to event handlers in code behind and use the navigation model with view models as parameters. I can post an example if needed, but there is nothing special in that code. What could cause a event-bound button to appear to be pressed but not call the handler, on some environments?
Extracts from one of the main features that the testers mention as non-functional:
View:
<GridView ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
ItemClick="ItemView_ItemClick"..
Code behind:
void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
var foodItem = (FoodItemViewModel)e.ClickedItem;
var mainViewModel = (MainViewModel)this.DefaultViewModel["MainViewModel"];
mainViewModel.CurrentItem = foodItem;
this.Frame.Navigate(typeof(ItemDetailPageReadOnly), (MainViewModel)mainViewModel);
}
From ItemDetailPageReadOnly:
protected override void LoadState(Object navigationParameter,
Dictionary pageState)
{
if (pageState != null && pageState.ContainsKey("SelectedItem"))
{
navigationParameter = pageState["SelectedItem"];
}
var mainVm = (MainViewModel)navigationParameter;
this.DefaultViewModel["MainViewModel"] = mainVm;
this.DefaultViewModel["Item"] = mainVm.CurrentItem;
}
I would expect a NullPointerException if any of the parameters were null, not the described behavior from the testers.
you should use one of the higher level events unless you need to respond to a specific portion of the gesture. http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh994936.aspx

Fast App Resume issues in windows phone 8

When i set ActivationPolicy="Resume" in WMAppManifest.xml page tile navigation(navigation URL) is not working in Tombstone state, it reloads the last back stack page(URL). It works fine with Dormant state with out reloading the page. If don't set this property (ActivationPolicy="Resume") it reloads the page in both states [Dormant state and Tombstone state].
But how can we achieve the navigation to secondary url's, when we set that property.
Please help me .
Adding ActivationPolicy="Resume" is not the only step needed to have your app support Fast App Resume. I believe the behavior you are describing is normal when you only set that one property. I think there are a few ways to implement "Fast App Resume", but I found this to be the easiest way.
Set the activation policy like you just described and then do the following:
Go into App.xaml.cs in the "App" class add:
private bool reset
You should then have a method for InitializePhoneApplication that initializes the RootFrame. Add this:
RootFrame.Navigating += RootFrame_Navigating;
RootFrame.Navigated += RootFrame_Navigated;
Then you can go and add those methods:
void RootFrame_Navigating(object sender, NavigatingCancelEventArgs e)
{
if (reset && e.IsCancelable && e.Uri.OriginalString == "/MainPage.xaml")
{
e.Cancel = true;
reset = false;
}
}
void RootFrame_Navigated(object sender, NavigationEventArgs e)
{
reset = e.NavigationMode == NavigationMode.Reset;
}
If you implement this properly, your app should resume from the last page you were on.
Same problem here. I got WP8 application with Fast App Resume enabled. I can pin tiles pointing to specific pages in my apps. It works fine when app is just Suspended, but when the app is Tombstoned, then clicking secondary tile has the same effect as clicking the main tile.
I receive only one RootFrameNavigating event with NavigationMode == Back and Uri == /MainPage.xaml. The app then shows the previous page that was there before I suspended the app.
I guess this is actual bug in the platform for this specific scenario - Fast App Resume + tombstoned app + navigation from pinned tile, that we as developers cannot solve.