Why is setCenter implementation inconsistent on mobile v. laptop? - mobile

I have some very straightforward code that works fine on my laptop running Chrome, but not on my Android (Gingerbread 2.3.6) browser:
window.addEventListener("resize", handleResize, false);
//define Map ("map") and LatLng ("myLoc")
function handleResize() {
if( map != null ) {
map.setCenter(myLoc);
//test to see if device knows it has been resized
var w1 = $(mapDiv).width();
alert(w1 + " " + myLoc);
}
}
As you can see, all I'm doing is trying to recenter after a resize event. Any idea why this doesn't work on my phone? (And, yes, the phone knows it's been resized.)

Related

GetWindowRect returning wrong coordinaties

i'm developing VSTO add-in for outlook which includes overlay on top of the window.
I'm building my UI using WPF.
Problem is that when i'm trying to attach WPF Window ( merge left/top/width/height ) to outlook window when STARTING at scale more than 100% GetWindowsRect Returns wrong rectangle.
BUT when i'm starting application at 100% scale then change windows scale at runtime to whatever value everything is good and DPI Aware. Both cases ( starting and runtime ) GetDpiForWindow returns correct values which is...strange. DPI Awareness is set using SetThreadDpiAwareness when forms are created.
Can't get my head what's wrong :<. Any advises appreciated.
Code for attaching:
public void AttachTo(IntPtr src, AttachFlagEnum flags)
{
var nativeRectangle = new WinAPI.RECT();
if (!WinAPI.GetWindowRect(src, ref nativeRectangle))
{
// throw new Win32Exception(Marshal.GetLastWin32Error());
return;
}
AttachToCoords(new Rectangle(nativeRectangle.Left, nativeRectangle.Top, nativeRectangle.Right - nativeRectangle.Left, nativeRectangle.Bottom - nativeRectangle.Top), flags);
}
Form create code:
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
StateManager.Init();
OutlookUtils.WaitOutlookLoading();
using (var ctx = new DPIContextBlock(WinAPI.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE))
{
new Forms.One().Show();
new Forms.Overlay().Show();
new Forms.Two();
}
}
Overlay attach code (executes by timer )
private void OverlayThink(object ob)
{
if (Managers.StateManager.OutlookState == OutlookStateEnum.MINIMIZED || Managers.StateManager.UiState == UIStateEnum.DESCWND)
{
if (this.IsVisible)
{
this.Dispatcher.Invoke(() => this.Hide());
}
return;
}
this.Dispatcher.Invoke(() => this.AttachTo(Utils.OutlookUtils.GetWordWindow(), AttachFlagEnum.OVERLAY));
this.Dispatcher.Invoke(() => this.Show());
}
My solution to the problem was that AttachToCoords method sets coords from GetWindowRect directly to Window.Left | Right | Top | Bottom. That's wrong because internally WPF positions it's elements in 96 DPI coordinate system. So i was need to convert it before assigning.
Solution:
private Rectangle TransformCoords(Rectangle coords)
{
var source = PresentationSource.FromVisual(this);
coords.X = (int)(coords.X / source.CompositionTarget.TransformToDevice.M11);
coords.Y = (int)(coords.Y / source.CompositionTarget.TransformToDevice.M22);
coords.Width = (int)(coords.Width / source.CompositionTarget.TransformToDevice.M11);
coords.Height = (int)(coords.Height / source.CompositionTarget.TransformToDevice.M22);
return coords;
}
WPF (as well as Windows forms) should be scaled automatically depending on the DPI value set on the system. There is no need to calculate the size and positions of the dialog window in Outlook add-ins.
Instead, you need to set up the form correctly to follow the DPI settings and set the window parent, so it will be displayed on top of the Outlook window.

When videos are just loaded or paused, they are completely black (on Android)

This happens on Android only. Videos work properly on iOS and Simulator.
The problem is that when my videos are loaded into the MediaPlayer, the displayed frame is and remains completely black. After pressing play, the video displays correctly. By pressing pause, the frame on which the pause occurred is shown correctly. However, if the app switches to background and then back to foreground, the paused video goes back to completely black.
How can I fix this problem?
The relevant part of my code is more or less as follows:
Media video = MediaManager.createMedia(videoFilePath, true, () -> {
Runnable callback = runOnVideoCompletion.get();
if (callback != null) {
callback.run();
}
});
video.setNativePlayerMode(false);
video.prepare();
MediaPlayer mediaPlayer = new MediaPlayer(video) {
#Override
public Dimension getPreferredSize() {
return new Dimension(size, size);
}
};
mediaPlayer.setHideNativeVideoControls(true);
mediaPlayer.setMaximize(false);
mediaPlayer.hideControls();
mediaPlayer.setAutoplay(false);
Container mediaPlayerCnt = new Container(new LayeredLayout(), "NoMarginNoPadding") {
#Override
public Dimension getPreferredSize() {
return new Dimension(size, size);
}
};
mediaPlayerCnt.add(mediaPlayer);
[...]
UPDATE: please see the comment Reduce the impact of videos in memory to prevent crashes, since there is a better approach than the solution I proposed here.
While waiting for a proper solution, I came up with a workaround that seems to solve the problem perfectly on my Android phone.
This code is in a method invoked to create each video and is therefore executed before form.show(), so the UITimer runnable is invoked about half a second after the form is shown.
/*
* Workaround for the issue: https://stackoverflow.com/q/66144759
* "video" is a Media instance returned by MediaManager.createMedia
* This workaround is for Android only and it assumes we don't use autoplay
*/
if (form != null && DeviceUtilities.isAndroidNative()) {
UITimer.timer(500, false, form, () -> {
CN.invokeAndBlock(() -> {
video.play();
video.setVolume(0);
while (!video.isPlaying()) {
/*
* When in a scrollable container there are many videos,
* play does not start immediately, but only when the
* video becomes visible, so we must wait.
*/
Util.sleep(100);
}
Util.sleep(100); // extra wait to be sure that the waiting is not zero
video.pause();
video.setVolume(100);
});
form.addShowListener(l -> {
CN.invokeAndBlock(() -> {
video.play();
video.setVolume(0);
while (!video.isPlaying()) {
// same as above
Util.sleep(100);
}
Util.sleep(100); // as above
video.pause();
video.setVolume(100);
});
});
});
}

CN.setScreenSaverEnabled(false); and MediaPlayer

Oddly when I play a video using MediaPlayer in a non-native way, after a few seconds (depending on the mobile phone settings) the power saving mode starts, which turns the screen off. This is an unwanted behavior, because when playing a video the screen must never turn off or dim. I don't understand if this is a Codename One bug or a feature, however it happens both on Android and iOS.
Apparently I fixed the problem using CN.setScreenSaverEnabled(false);. My problem, however, is that it doesn't work all the time. The following code sometimes makes the screen stay active, sometimes it doesn't. I don't understand why sometimes it works and sometimes it doesn't.
To better understand the following code, videoUrl is an HLS stream.
private void playVideo(Form parent, String videoUrl) {
CN.setScreenSaverEnabled(false);
Form player = new Form(new BorderLayout());
player.getToolbar().setBackCommand("Back", Toolbar.BackCommandPolicy.ALWAYS, e -> {
if (mp != null) {
mp.getMedia().cleanup();
}
CN.setScreenSaverEnabled(true);
parent.showBack();
});
player.add(BorderLayout.CENTER, FlowLayout.encloseCenterMiddle(
new SpanLabel("Stream will start playing automatically when it is live")));
player.addShowListener(l -> {
while (!Util.downloadUrlToStorage(videoUrl, "temp.m3u8", false)) {
CN.invokeAndBlock(() -> Util.sleep(1000));
}
try {
// note that we cannot play the locally downloaded m3u8
Media video = MediaManager.createMedia(videoUrl, true, () -> {
// completion handler, it's invoked when the stream connection is lost
if (mp != null) {
mp.getMedia().cleanup();
}
CN.setScreenSaverEnabled(true);
parent.showBack();
});
video.setNativePlayerMode(false);
if (mp != null) {
mp.getMedia().cleanup();
}
mp = new MediaPlayer(video);
mp.setAutoplay(true);
mp.setHideNativeVideoControls(true);
mp.setMaximize(false);
player.removeAll();
player.add(BorderLayout.CENTER, mp);
player.revalidate();
} catch (Exception err) {
Log.e(err);
ToastBar.showErrorMessage("Error loading straming");
}
});
player.show();
}

Adding mousewheel to Sencha Desktop App

So the supposed advantage to using Sencha is being able to have 1 code base for multiple platforms. I have a project I need to be on iOS, Android, PC, and Mac. I have found that I can use Sencha Touch to build to mobile devices and those handle finger swipe events automatically. The problem I have encountered is when I am building a desktop app then it doesn't respond to my mousewheel.
I have been on the Sencha forums and this question is unanswered in one place, and in another they promised support for this over 2 years ago. Any 3rd part solutions I have found either are not documented properly or won't work. Elsewhere I have been told that Sencha Touch is for mobile development but Extjs is for desktop, but I really don't want to have to build another codebase just for mousewheel.
There is a JSfiddle here where delta returns 1 when you mousewheel up, and -1 when you mousewheel down.
var doScroll = function (e) {
// cross-browser wheel delta
e = window.event || e;
var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
// Do something with `delta`
console.log(delta);
e.preventDefault();
};
if (window.addEventListener) {
window.addEventListener("mousewheel", doScroll, false);
window.addEventListener("DOMMouseScroll", doScroll, false);
} else {
window.attachEvent("onmousewheel", doScroll);
}
Put this code into the initialization block for your app. Now this code will get run anywhere in your app no matter which element has focus. I was lucky enough in my app that each of my pages only had 1 element that needed to be scrolled.
replaced console.log(delta); with code that determines which element is active/which element was in need of scrolling, and the code to scroll it.
var scrollMe = Ext.getCmp("componentToScroll");
var currentY = scrollMe.getScrollable().getScroller().position.y;
var pageHeight = document.getElementById("orderList").clientHeight;;
var containerHeight = 722; //the defined height of the scrollMeContainer
var newY = currentY;
if (delta === 1) {
if (currentY >= 30) {
newY = currentY - 30;
}
else {
newY = 0;
}
}
else if (delta === -1) {
if (currentY <= containerHeight - pageHeight - 30) {
newY = currentY + 30;
}
else {
newY = containerHeight - pageHeight;
}
}
scrollMe.getScrollable().getScroller().scrollTo(0, newY);

NetConnect fails silently in Flash when called from SilverLight

This is a complex question, because there are a lot of moving parts. My apologies in advance.
I'm trying to write a Silverlight control that hosts a Flash camera and microphone (since Silverlight doesn't support these things natively, worse luck). I've written a short little Flex application ("WLocalWebCam.swf") which handles the camera, and exposes two external methods: connect(uri:String, streamName:String), and disconnect(). I can call these successfully through JavaScript as follows (simplified to remove error handling, etc.):
function connectWebCam(webCamID, rtmpUri, streamName) {
var flashCam = getWebCam(webCamID);
flashCam.Connect(rtmpUri, streamName);
}
function disconnectWebCam(webCamID) {
var flashCam = getWebCam(webCamID);
flashCam.Disconnect();
}
function getWebCam(id) {
return document.getElementById(id);
}
When I call these functions from another JavaScript source (e.g., a button click handler), the web cam connects correctly up to the RTMP server (I'm using Wowza). However, when I call exactly these same functions on the same page from Silverlight, the Flash camera fails to connect to the RTMP server.
/// <summary>
/// Connect() invokes the connectWebCam() JavaScript function contained in the WebCam.js file on the website.
/// The connectWebCam() method in turn calls the Connect() method on the contained Flash web cam object.
/// </summary>
public void Connect()
{
ScriptObject connectWebCam = (ScriptObject)HtmlPage.Window.GetProperty("connectWebCam");
connectWebCam.InvokeSelf(CameraID, RtmpUri.ToString(), CameraID);
}
However, it fails in an interesting fashion. The ActionScript connect() method gets called, it successfully calls getConnection(), but the handleNetStatus event handler method never gets called, and the Wowza server never sees an attempt to connect.
Here's the ActionScript code I'm using, this time with the debugging bits left in.
public function connect(uri:String, name:String):void
{
rtmpUri = uri;
streamName = name;
logMessage("Beginning attempt to open connection; rtmpUri=" + rtmpUri + "; streamName = " + streamName);
logMessage("Retrieving camera.");
cam = Camera.getCamera();
if( cam != null )
{
logMessage("Retrieved camera.");
cam.setMode( 320, 240, 20 );
cam.setQuality( 0,0 );
}
else
{
logMessage("Unable to retrieve camera instance.");
}
logMessage("Retrieving microphone.");
mic = new Microphone();
if (mic == null)
{
logMessage("Unable to retrieve microphone instance.");
}
logMessage("Retrieving NetConnection.");
chatNC = getConnection();
}
private function getConnection(): NetConnection
{
var nc: NetConnection = new NetConnection();
if (nc != null)
{
logMessage("Retrieved NetConnection().");
nc.client = this;
nc.objectEncoding = ObjectEncoding.AMF0;
nc.addEventListener( NetStatusEvent.NET_STATUS, this.handleNetStatus );
logMessage("Connecting to " + rtmpUri);
nc.connect(rtmpUri); // <-- We get successfully to this point.
}
else
{
logMessage("Unable to retrieve new NetConnection()");
}
return nc;
}
private function handleNetStatus( event:NetStatusEvent ):void
{
logMessage("[SYSTEM MESSAGE] net status " + event.info.code + " type " + event.type); // <-- We never get this far. This bit never gets called.
switch( event.info.code )
{
case "NetConnection.Connect.Success":
publishVideoStream();
break;
default:
Alert.show("Error connecting: " + event.info.code, "Error Connecting");
break;
}
}
This has got me seriously scratching my head.
Does anyone know why the exact same ActionScript would behave differently if called from Silverlight vs. being called from JavaScript? Any suggestions on troubleshooting it?
Sigh. Never mind. Turns out it makes a difference if you try to connect to http://localhost/videochat instead of rtmp://localhost/videochat. It all works as expected when you give it the right parameters. I must have looked at that code a hundred times before I spotted what I did wrong.

Resources