Apple TV as an external UIScreen on an iOS device - c#

I have an app that displays video in a subview and where it would be nice to give the option to display that video on a second screen such as an Apple TV and be able to use that freed-up space to show additional controls.
I've found all sorts of help about how to do that, but I'm hitting a wall even before getting out of the starting gate.
In order to detect that the app has started up in a multiple display environment, all the sample code features a line like...
if (UIScreen.Screens.Length > 1) {
// ...
}
(I'm doing this in C#/Xamarin, though I doubt the problem is related to that; anyway, the snippets are in C#)
My problem is that the array of screens is always 1 no matter what I do. The iPad is running iOS 11.2.5, and if I turn on mirroring, the iPad is mirrored, but , again, the array of screens only has a single item.
There are also a couple of observers to detect screens being added/removed while the app is running. I haven't seen Xamarin specific code, but I presume it looks like:
NSNotificationCenter.DefaultCenter.AddObserver(this, UIScreen.DidConnectNotification, NSKeyValueObservingOptions.New, IntPtr.Zero);
NSNotificationCenter.DefaultCenter.AddObserver(this, UIScreen.DidDisconnectNotification, NSKeyValueObservingOptions.New, IntPtr.Zero);
Anyway, those never fire even if I add/remove the Apple TV or enter/exit Mirroring Mode on the iPad.
Oh; also if I do
avPlayer.AllowsExternalPlayback = true;
avPlayer.UsesExternalPlaybackWhileExternalScreenIsActive = true;
then that works as expected, too. The video now appears full-screen on the Apple TV and the UIView on the iPad containing the avPlayer greys out rather than showing the video.
However, that's not what I'm looking for. I would like to control the layout of both screens and that does neither. (While I do want the video to be full screen on the Apple TV, I don't want it to be an AVPlayerViewController and I do want to repurpose the screen real-estate taken up by the iPad video view)
At the end of the day, all I think I need is to manage to get
UIScreen.Screens.Length to be equal to 2 when I launch the app.
What's the secret of getting UIScreen to detect/report a second display?

When an app is launched with screen mirroring already enabled, the UIScreen.screens array initially only contains the device's screen. Shortly after launch, iOS posts a UIScreenDidConnect notification to advise your app that a second screen is connected.
What you will see at launch is that the captured property of your main screen is true if mirroring is enabled, however you can't actually access the second screen until after the notification is posted. Note that captured could also indicate that screen recording is in progress.
Although this seems slightly counter-intuitive it actually makes your coding a little simpler; you need to observe the UIScreenDidConnect and UIScreenDidDisconnect notifications anyway and now you don't need to write any special code to handle the case where the app is launched with a second screen already attached.
You can use something like this in your didFinishLaunching:
let nc = NotificationCenter.default
nc.addObserver(forName: NSNotification.Name.UIScreenDidConnect, object: nil, queue: nil) { (notification) in
print("Screen connected")
self.enableExternalDisplay()
}
nc.addObserver(forName: NSNotification.Name.UIScreenDidDisconnect, object: nil, queue: nil) { (notification) in
print("Screen disconnected")
self.disableExternalDisplay()
}
UPDATE
Actually, it looks like you have the key/value observing format of AddObserver in your code, when you actually want notification observing. Something like:
NSNotificationCenter.DefaultCenter.AddObserver(UIScreen.DidConnectNotification,OnScreenConnected)
And then you need to implement an OnScreenConnected method.

Related

ViewManagement.FullScreenSystemOverlayMode and taskbar visibility

I am developing Windows 10 Universal App using C#. My question is refers to a case when an user runs my application on PC/desktop.
I want my app to be full screen, this can by done by calling
Windows.UI.ViewManagement::TryEnterFullScreenMode()
Now we are in full screen. But when user swipes mouse pointer to lower edge of the screen Windows' Taskbar will appear and I don't want it to appear - what can I do?
I've tried setting FullScreenSystemOverlayMode property of corresponding Windows.UI.ViewManagement to FullScreenSystemOverlayMode.
Minimal alongside with setting SuppressSystemOverlays to true.
Neither has helped, what can I do?
When I do something like that I use:
ApplicationView.GetForCurrentView().SuppressSystemOverlays = true;
ApplicationView.GetForCurrentView().FullScreenSystemOverlayMode = FullScreenSystemOverlayMode.Minimal;
ApplicationView.GetForCurrentView().TryEnterFullScreenMode();
Maybe just semantics, but sometime those semantics matter.

MonoGame - Working With Specific Gestures for Different Purposes

Part of my particular dilemma is that I would like to be able to get the initial position of a drag gesture. Depending on the initial position of that drag gesture, the application would either 1) pan the view or 2) display a menu, but not perform these gestures at the same time (which is where part of struggle lies).
For example, if the user initiated a drag from the very left side of their screen and dragged inwards, a menu would pop in instead of the view panning.
I would also like to be able to execute a double tap gesture without also activating a tap gesture, if that's at all possible. I've tried working with boolean flags - for example,
// ...
if (gesture.GestureType == GestureType.DoubleTap)
{
isDoubleTap == true;
}
// ...
public static Vector2 Tap
{
get
{
if (!isDoubleTap)
return gesture.Position;
// ...
But that doesn't work.
I've tried using TouchCollection - if anyone would like me to elaborate on my issues with that I can, but for now I'll say what I tried hasn't worked. It's entirely possible I may have just goofed as I am a novice when it comes to working with touch input.
I've been working on this for a few days and have done as much searching as I can, and nothing I've found has alleviated my issue - if I happened to have missed something, I apologize.
Thank you for your time!
Concerning start position of a drag:
There is a gesture for a drag ending, so if you receive a drag and its the first one since the last drag ended, thats the initial position.
Concerning tap/doubletap:
MonoGame works the same way as XNA as documented here:
The user tapped the screen twice in quick succession. This
always is preceded by a Tap gesture.
This sounds like a input-bindings design problem more than a technical question imo. Consider also what you can move to instead occur on press or release rather than only making use of gestures.

Check if webpage is run on tablet

For my Asp.Mvc 5 project, I have a horizontal menu, like; Home, Products, about, etc.
For that menu, I have used some CSS styling to make it collapse into a dropdown menu, if the page size is getting reduced, or the resolution is low:
#media screen and (max-width: 767px) {
.headerNavigation{
....
...
}
}
This works fine on my laptop and PC ; if the width of the browser gets below 767px, it will make it to a drobdown instead. This was so it would not start putting the last <li> below the first<li>.
The thing is, it doesnt work on tablets, as the resolution is usually high there. But the last <li> will still be moved below the first one, as the screen size is smaller.
So my question is: Is there a way to check, if your Mvc5 webpage is running on a tablet? Or is there a better way to handle something like this ?
Maybe you should consider responsiveness?
It is better than simple #media statements if you expect the page to be displayed on many devices like PC/tablet/smartphones.
Take a look here: https://www.google.com/search?q=css+responsive+tutorial
You should not try to "detect" a tablet. Your web should be fluid as a river that borns tiny in the mountain and gets huge when gets to the sea: you get water all along.
Smartphones are getting bigger and maybe in a near future a smartphone will enter in you "tablet" mediaquery.
Your website should look fine in all.
Anyway, if you want to detect your device, you can do that server side with PHP script like PHP Mobile Detect
I'm not a programmer, but my developers here in the office tells me that you can archive the same in .NET.
Tablets prefer to scale webpages, give it a try with portrait:
#media only screen and (orientation:portrait) {
.headerNavigation{
...
}
}
Assuming the menu should show as normal when on landscape.

WP7 Pivot control and a WebBrowser control

I have a Pivot which contains a WebBrowser control that practically takes up the whole page (appart from the Pivot header of course).
I would like to figure out how to make the WebBrowser control allow for the user to swipe left/right to activate the Pivot control. Currently it just pans the WebBrowser control left/right
Can this be done??
Thank
While I cannot tell you exactly how to pass the swipes to the pivot, I can tell you how to do a part of the job: how to catch/analyze/disable custom gestures over the WebBrowser.
If I remember correctly, in the 7.0:
the WebBrowser component consisted almost only of an internal TileHost wrapped in some grids/borders
the TileHost did all the work related to processing touch events
the TileHost did it completely internally (in the native layer), without the .Net seeing any manipulation-events (I think), or at least it ignored all the attempts to handle/override the manipulation-event on the upper layer. The WebBrowserInterop class was mostly empty in these matters.
Now, in the 7.5 that I have (maybe on 7.1 too, I dont know), it seems that the MS is working really hard on some WebBrowser manipulation problems --- I think they are working towards having the scrolling/swiping fully processed by the .Net layer. They have written a special class PanZoomContainer and injected them into the VisualTree of WebBrowser's internal template. The WebBrowserInterop was greatly enriched with many tunnels for event notifications. The WebBrowserInterop hooks into PanZoomContainer's ManipulationEvents, then passes them to the native layer. Also, it listens to events/commands from the native layer, called for example "ZoomAndScroll" or "ShowSIP" - and mostly passes them back to the PanZoomContainer. The idea is crystal clear right? They have rewired the event handling from completely-internal to a bit of spaghetti, but have achieved passing them through the PanZoomC.
Now, whats in that for me/us?
It is the PanZoomContainer, whose Mani-Events are inspected. The TileHost does not capture them now. In this version of the WebBrowser control, it's VisualTree consists of some borders, grids, a PanZoomContainer and a TileHost (the renderer). It is similar to that:
WebBrowser
PanZoom
ContentPresenter
Border/Name="border" <- you want this one
TileHost
I've skipped a few Borders and Grids, they are mostly irrelevant to the problem. Now, if the PanZoomContainer's Mani-Events are listened to, let's block them!
Using VisualTreeHelper, just dig deeper and deeper until you find a FrameworkElement.Name=="border". This is the border that wraps the TileHost that is the "renderer" that takes 99% space of the control. Be warned that there's a ContentPresenter, so you may have to wait until the controltemplate gets instantiated (ie. Loaded/LayoutUpdated).
Once you have your hands on that Border, attach all Mani-Event handlers to it: started, delta and completed. PanZoom is a normal xaml/silverlight/.net/etc control, so it actually obeys e.Handled = true :) Now, if you want to disable ie. vertical scrolling, filter the Delta and Completed events for Translation.Y<>0. If you want to disable tapping but leave srolling/panning - filter X==0&Y==0.
And that was the easy part.
The hard part is to experiment with filtering on different Start/Delta/Stop and adjusting the behaviour to your likes.
Although it might look very nice and tempting, this will NOT get you any real/nice results easily. For example, I wrote "if you want to disable vertical scrolling, then set a filter 'if y==0 then e.handled=true' ". Great? easy? Not!
Assume we want to "disable bouncy horizontal panning" while leaving "vertical scrolling". or vice versa, whatever, it is only an example:
Here's a small rectangular device with a sensitive touchscreen. Please make such a vertical swipe/pan/drag on the screen, that the resulting X-compound will be ZERO. If you set such filter, it will be almost impossible to it properly. Your users will want to kill you for forcing them to retry-that-vertical-scrolling for five or more times, until they make a perfect vertical swipe.
Of course you can make it not ==0, but leave some small margin. ok. But if you make the margin too big, the control will catch the intermediate offaxis movement and make a tiny horizontal pan also.. After a few unlucky vertical swipes, the total horizontal pan may accumulate from those small leftovers will accumulate and the diplacement maybe will be noticeable.
But there's some another vile side effects:
Saying shortly, you have commited e.Handled=true. The event is GONE. Dead. Deased. if you just wanted the WebBrowser to SKIP for example horizontal swipes, so that the outer (Pivot) control notices them and processes..... whoops. The event is GONE. Earlier, the TileHost/PanZoomC have extinguished the events, now you have it done yourself. Sounds like a bad joke, eh?
Fortunatelly:
since you have attached your handlers to the bottommost "border", they may not only block the events, but may also actually listen&publish them elsewhere. That is, if those handlers detect an interesting movement, they may e.Handled=true on it, but at the same time they can notify your custom objects about that discovery, and ie. start your storyboards.
mani-events are at hand, but there is also a second layer that listens to the manipulations: the GestureListener/GestureService from the Silverlight Toolkit. It reports events after they are handled by mani-events, but it reports them with no regard to any e.Handled=true that were set on them. It is completely separate gesture-listening mechanism, and you can also use it to detect manipulations that were 'cancelled'
.. and so the fun goes like that and maybe even a little further.
This is similar to putting a Map inside a Pivot - which is discussed here - http://mine.tuxfamily.org/?p=111 - already mentioned in quite a few questions - https://stackoverflow.com/search?q=mine.tuxfamily.org
In general, the advice seems to be usability based:
try to avoid putting controls which use Touch inside the PivotItem's
As an aside, if you are just using the web browser control for a very small amount of static html (so you don't need any scrolling at all) then you could just remove HitTesting from the web browser.
I do not know WP7 Pivot, but are there any Preview* events on the Pivot control that allow you to handle the touches and mark them as processed?
Call the below method and pass your parameter as PivotControl x:name and WebBrowserControl x:name to this method.
Here the WebBrowserControl is placed in second pivot item i.e. Pivot Index is 1 and I am trying to swipe left or right and reach to pivot index 2 or 1 respectively.
public static void SwipteLeftRight(Microsoft.Phone.Controls.Pivot pivotControl, Microsoft.Phone.Controls.WebBrowser webBrowserControl)
{
var gesListener = GestureService.GetGestureListener(webBrowserControl);
gesListener.Flick += ((sen, args) =>
{
if (args.Direction == System.Windows.Controls.Orientation.Horizontal)
{
if (args.HorizontalVelocity < 0)
{
if (((Microsoft.Phone.Controls.PivotItem)(pivotControl.SelectedItem)).Header.ToString().Trim() == "Pivot Item name")
{
pivotControl.SelectedIndex = 2; //Next Pivot item
}
}
else if (args.HorizontalVelocity > 0)
{
if ((Microsoft.Phone.Controls.PivotItem)(pivotControl.SelectedItem)).Header.ToString().Trim() == "Pivot Item name")
{
pivotControl.SelectedIndex = 0; // Previous Pivot Item
}
}
}
});
}
It worked for me. Cheers

Take Screenshot of a custom listclass

There is a program with a long list, from which I would like to take screen shots from. The Problem is, that there are only 14 of about 100 shown. How can I take a screen shot of the entire list?
The one approach that comes to my mind is basically send a PG-Down click to this list, take a new screen shot and merge them together. Are there any easier and quicker solutions for that?
You may grasp the concept from
http://www.codeproject.com/KB/graphics/IECapture.aspx &
http://www.codeproject.com/KB/dialog/windowsnapshot.aspx
and replace the window handle of IE by Custom listClass window

Categories