Details
-
Type: Bug
-
Status: Reopened
-
Priority: Major
-
Resolution: Unresolved
-
Affects Version/s: 1.0 Final
-
Fix Version/s: 1.4 Beta
-
Component/s: None
-
Labels:None
-
Environment:Android/ICEmobile
Description
-
- android.lidpcap
- 178 kB
- Steve Maryka
Activity
- All
- Comments
- History
- Activity
- Remote Attachments
- Subversion
The wireshark capture.
listen.icepush requests do not seem to continue after the link is played.
It's not yet certain if the push connection is suspended during video playback or what events might be available to restart it when the user stops watching the video.
Reload page when the application resumes activity from a paused state to ensure that ICEFaces bridge is initialized and registers for push notifications with the ICEpush bridge.
Previously only 'ice.push.connection.resumeConnection()' function was invoked which started the blocking connection but the page was not listening for push events.
A page reload seems heavy handed. The page is completely functional without a reload - except for push connection. A page load is very disruptive to the user experience.
Obviously the page is not completely functional otherwise we wouldn't have this issue. We could initialize the ICEfaces bridge programmatically but I don't know if the container has access to the ICEfaces bridge configuration or viewID of the page.
Fixing it in the container still leaves the stock browser with an issue, so that is not a great option. This issue seems specific to Android, so why is it not a problem on other platforms?
I understand that we have a problem in stock browser. Unfortunately , while debugging the app, I discovered that none of the page events are fired when returning to the page. So, 'onpageshow' or 'onload' will not fire hence the failure to fully setup the page.
It may be possible to use a history listener to restart the ICEfaces and ICEpush bridges.
Reverted previous fix.
The new fix modifies the audio renderer so that when the 'Play' link is clicked a new window is opened. This way the bridge belonging to the current page is not shut down. This solution work also on stock browser.
Similar change needs to be applied to VideoRenderer.
My current testing indicates that the stock browser on Android works fine with both Audio and Video links. Push keeps working after, but on Android container, push stops working after playing either audio or video links.
I am going to retest in detail to see where we stand on this issue.
I confirmed that this is still broken for both Audio and Video links. The container pauses and resumes the blocking connection as expected, but the blocking connection does not resume when returning from the Audio/Video link.
Testing on Nexus 7 tablet confirms that the blocking connection is not resumed after the video link is played.
The web console output indicates that ICEpush is attempting to connect with the server, but is receiving an error response. However, network monitoring shows no such HTTP requests.
postAsynchronously() is not invoked by the icepush JavaScript as isEmpty(lastSentPushIds) returns true after the video link is played.
The request for the video file from the container causes the pushids cookie to be cleared (notice the "ice.pushids="):
GET /mobileshowcase/javax.faces.resource/945495df-801a-4f79-8fa9-9a017344edb5.jsf;jsessionid=6A51B4309586E2DFA54135357D33AE76 HTTP/1.1
Host: tetra.ice:8080
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
X-Requested-With: org.icemobile.client.android
User-Agent: Mozilla/5.0 (Linux; U; Android 4.2.1; en-us; Nexus 7 Build/JOP40D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30
Accept-Encoding: gzip,deflate
Accept-Language: en-US
Accept-Charset: utf-8, iso-8859-1, utf-16, *;q=0.7
Cookie: com.icesoft.user-agent=HyperBrowser/1.0; JSESSIONID=6A51B4309586E2DFA54135357D33AE76; com.icesoft.user-agent=HyperBrowser/1.0; com.icesoft.user-agent=HyperBrowser/1.0; ice.push.browser=2hbzmz0j7; ice.connection.contextpath=%2Fmobileshowcase; ice.connection.running=f35ed:acquired; ice.connection.lease=1358292382056; ice.pushids=
delistPushIDsWithBrowser() is being invoked when the video is played resulting in the list of pushIDs being empty.
When the video is displayed, onBeforeUnload is invoked
onBeforeUnload(window, function()
{ delistPushIDsWithBrowser(pushIdentifiers); pushIdentifiers = []; });
However, the page is not reloaded when the video completes.
Is it possible for the container to reload the current page when the video or audio playback completes? I believe this would cause ICEpush to resume correctly.
As this only seems to happen when you run video in full screen mode, perhaps we could use the media events to check if the page does need to be refreshed:
function checkIfPushIdsEnlisted(elem)
{ var pushIdentifiers = lookUpPushIdsFromCookie(); elem.setAttribute('data-pushIds', pushIdentifiers); }function refreshIfPushLost(elem){
var pushIdentifiers = lookUpPushIdsFromCookie();
if( elem.getAttribute('data-pushIds') && !pushIdentifiers )
}
video.addEventListener("loadeddata", checkIfPushIdsEnlisted, false);
video.addEventListener("ended", refreshIfPushLost, false);
In this case the video is just a link to a file – would there be a video object available to JavaScript?
I also wonder if the page containing the link is actually "unloaded" at this point. The video playback may actually be a popup window (in that case the original unload even should never have been called).
No, using the video object wouldn't work for clicking the external link.
onbeforeunload is called as soon as you click the link. And unfortunately onload is not called when returning to the page after the video finishes.
What about just not rendering the 'Play' external link on the android container. We already do the same for iOS. We can note it as a known issue and users can always add their own link manually.
Using video conversion on labs the behavior on the iPad is improved, but playback is still not successful. The conversion script will need to be updated.
It may be possible to allow multiple windows and avoid the onBeforeUnload (since the video link has a target="_blank" attribute):
WebSettings settings = webView.getSettings();
settings.setSupportMultipleWindows(true);
The above suggestion did not work. WebChromeClient.onWindowCreated() is never called. Can't find any threads on the web that solves the problem.
If we could modify the URL to the video resource to include something uniquely recognizable, we might be able to use WebViewClient.shouldOverrideUrlLoading() to do something different.
Once the video starts playing, the container does an onPause which is calling pauseBlockingConnection, but it is already gone because of the page unload. Maybe pauseBlockingConnection could be smarter.
A few solutions are possible:
- modify Android container so that onBeforeUnload is not called for full screen video playback
- modify Android container so that page is reloaded when full screen video playback completes
- modify ICEpush so that the cookie is not cleared in onBeforeUnload. For instance, on Android WebKit client-side storage could be used and the current list of PUSHIDs should be built up from the current PUSHIDs in each JavaScript memory space in each responding window
I have not been able to find any client side mechanism to reliably detect when VideoViewer is activated to play a video or audio clip. The WebChromeClient.onShowCustomView() is the mechanism that is supposed to be used, but apparently it does not work as of 4.0. We need to consider an ICEpush-based approach. The container is diligently pausing and resuming the blocking connection when the video plays.
ice.setupPush('vgkhrkf9');
Cookie: com.icesoft.user-agent=HyperBrowser/1.0; JSESSIONID=D3D49F70A9150E26876EA5D847DBF08B; com.icesoft.user-agent=HyperBrowser/1.0; ice.push.browser=1heq42673; com.icesoft.user-agent=HyperBrowser/1.0; ice.pushids=vxa54j65%20vxa54j68%20vgkhrkf9
POST /mediacast/javax.faces.resource/listen.icepush.xml.jsf
ice.pushid=vxa54j65&ice.pushid=vxa54j68&ice.pushid=vgkhrkf9
GET /mediacast/javax.faces.resource/43785373-60f3-4727-964d-64a3b2a64bed.jsf;jsessionid=D3D49F70A9150E26876EA5D847DBF08B
Cookie: com.icesoft.user-agent=HyperBrowser/1.0; JSESSIONID=D3D49F70A9150E26876EA5D847DBF08B; com.icesoft.user-agent=HyperBrowser/1.0; ice.push.browser=1heq42673; com.icesoft.user-agent=HyperBrowser/1.0; ice.connection.contextpath=%2Fmediacast; ice.connection.running=2a042:acquired; ice.connection.lease=1364248744765; ice.pushids=vxa54j65%20vxa54j68
POST /mediacast/javax.faces.resource/listen.icepush.xml.jsf
ice.pushid=vxa54j65&ice.pushid=vxa54j68
X-Connection: close
X-Connection-reason: duplicate
GET /mediacast/javax.faces.resource/43785373-60f3-4727-964d-64a3b2a64bed.jsf;jsessionid=D3D49F70A9150E26876EA5D847DBF08B
User-Agent: stagefright/1.2 (Linux;Android 4.2.1)
POST /mediacast/javax.faces.resource/listen.icepush.xml.jsf
Cookie: com.icesoft.user-agent=HyperBrowser/1.0; JSESSIONID=D3D49F70A9150E26876EA5D847DBF08B; com.icesoft.user-agent=HyperBrowser/1.0; ice.push.browser=1heq42673; com.icesoft.user-agent=HyperBrowser/1.0; ice.connection.lease=1364248744765; ice.pushids=vxa54j65%20vxa54j68;
ice.pushid=vxa54j65&ice.pushid=vxa54j68
X-Connection: close
X-Connection-reason: duplicate
listen requests continue with ice.pushid=vxa54j65&ice.pushid=vxa54j68
Adding a button to the page that prevents pushIDs from being cleared during onunload:
ice.setupPush('vgkhrkfa');
POST /mediacast/javax.faces.resource/listen.icepush.xml.jsf
Cookie: com.icesoft.user-agent=HyperBrowser/1.0; JSESSIONID=D3D49F70A9150E26876EA5D847DBF08B; com.icesoft.user-agent=HyperBrowser/1.0; ice.push.browser=1heq42673; com.icesoft.user-agent=HyperBrowser/1.0; ice.pushids=vxa54j65%20vxa54j68%20vgkhrkfa;
ice.pushid=vxa54j65&ice.pushid=vxa54j68&ice.pushid=vgkhrkfa
GET /mediacast/javax.faces.resource/43785373-60f3-4727-964d-64a3b2a64bed.jsf;jsessionid=D3D49F70A9150E26876EA5D847DBF08B
Cookie: com.icesoft.user-agent=HyperBrowser/1.0; JSESSIONID=D3D49F70A9150E26876EA5D847DBF08B; com.icesoft.user-agent=HyperBrowser/1.0; ice.push.browser=1heq42673; com.icesoft.user-agent=HyperBrowser/1.0; ice.pushids=vxa54j65%20vxa54j68%20vgkhrkfa;
GET /mediacast/javax.faces.resource/43785373-60f3-4727-964d-64a3b2a64bed.jsf;jsessionid=D3D49F70A9150E26876EA5D847DBF08B
User-Agent: stagefright/1.2 (Linux;Android 4.2.1)
POST /mediacast/javax.faces.resource/listen.icepush.xml.jsf
Cookie: com.icesoft.user-agent=HyperBrowser/1.0; JSESSIONID=D3D49F70A9150E26876EA5D847DBF08B; com.icesoft.user-agent=HyperBrowser/1.0; ice.push.browser=1heq42673; com.icesoft.user-agent=HyperBrowser/1.0; ice.pushids=vxa54j65%20vxa54j68%20vgkhrkfa;
ice.pushid=vxa54j65&ice.pushid=vxa54j68&ice.pushid=vgkhrkfa
X-Connection: close
X-Connection-reason: duplicate
POST /mediacast/javax.faces.resource/listen.icepush.xml.jsf
Cookie: com.icesoft.user-agent=HyperBrowser/1.0; JSESSIONID=D3D49F70A9150E26876EA5D847DBF08B; com.icesoft.user-agent=HyperBrowser/1.0; ice.push.browser=1heq42673; com.icesoft.user-agent=HyperBrowser/1.0; ice.pushids=vxa54j65%20vxa54j68%20vgkhrkfa;
ice.pushid=vxa54j65&ice.pushid=vxa54j68&ice.pushid=vgkhrkfa
X-Connection: close
X-Connection-reason: duplicate
(I was originally recording this traffic to analyze the problem; on the last test push appears to continue to function, so it may be due to the device sleeping in between, or just inconsistent testing on my part.)
Experimentation with an ICEpush feature that prevents the unload from clearing the cookies does seem to help, but unfortunately the container onPause() is invoked after the page is unloaded.
It is likely necessary to define a new mechanism for clearing unused pushIDs. Disabling cleanup during onUnload allows push to continue functioning after the video is played, but it also results in an accumulation of old pushIDs. However, there are other cases where unused pushIDs accumulate, so an improved cleanup mechanism should be investigated.
Each browser window/tab has a set of pushIDs with active listeners. When a listen.icepush returns with a set of notifications, these need to be dispatched to the various browser windows via two mechanisms: local storage events and cookie polling. When a notification occurs (including a noop) each pushID in each window can have an associated timestamp so that the listening window can determine if a given pushID is still active. pushIDs with very old associated timestamps can be garbage collected.
This is an important fix so should be considered for 1.3EE.
I have captured http traffic to the Android device with wireshark. Here is the exact scenario, using mediacast
The traffic captured shows:
So the heartbeat continues but the notification never comes.