Blackberry progress bar during download - blackberry

I am working on an application for blackberry that will be downloading a file. I would like to show a progress bar during this download. I have tried every combination of GaugeField and ProgressIndicatorView that I can come up with but I am getting nothing. My download is going but the progress bar is never getting updated on the screen. In fact before I started trying for the progress bar I was trying to simply use a TextField and update it with the current percentage completed of the download, and I had no luck that way either.
This is inside my Screen:
view = new ProgressIndicatorView(0);
model = new ProgressIndicatorModel(0, 100, 0);
controller = new ProgressIndicatorController();
model.setController(controller);
view.setModel(model);
view.setController(controller);
controller.setModel(model);
controller.setView(view);
view.setLabel("Percent completion");
view.createProgressBar(Field.FIELD_HCENTER);
add(view);
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
downloadVideo();
initializeMedia();
// If initialization was successful...
if(_videoField != null)
{
createUI();
updateVideoSize();
try {
_player.start();
} catch (MediaException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ScreenSaverActivity.errorDialog("MEDIA EXCEPTION: "+e.toString());
}
}
else
{
_statusField.setText("Error: Could not load media");
}
}
});
downloadVideo() method:
private void downloadVideo(){
DownloadThread _dlThread = new DownloadThread();
_dlThread.start();
}
DownloadThread class:
class DownloadThread extends Thread {
public void run(){
try {
HttpConnection httpConn;
httpConn = (HttpConnection)Connector.open("http://url/to/myMovie.mp4");
InputStream is = httpConn.openInputStream();
String fName = "file:///store/BlackBerry/videos/myMovie.mp4";
FileConnection fconn = (FileConnection) Connector.open(fName, Connector.READ_WRITE);
if (!fconn.exists())
fconn.create();
OutputStream os = fconn.openOutputStream();
long lengthOfFile = httpConn.getLength();
int total = 0;
int count;
byte data[] = new byte[1024];
while ((count = is.read(data)) != -1) {
//I have tried this line outside of synchronized too, with no luck
synchronized(Application.getEventLock()) {
EmbeddedMediaScreen.this.model.setValue((int)(total*100/lengthOfFile));
}
total += count;
//write this chunk
os.write(data, 0, count);
}
os.flush();
os.close();
} catch (IOException e) {
ScreenSaverActivity.errorDialog(e.toString());
e.printStackTrace();
}
}
}
While my application is doing the download the device becomes unresponsive, so I am guess that my trouble is the download work is happing on the main(UI) thread for some reason and that this has something to do with why I can't get the screen to update with the progress. Any help would be greatly appreciated.
P.S. Android is generally my home, not blackberry, sorry if I have overlooked something that should be obvious =/

I see a few issues. It looks like the code after 'downloadVideo()' assumes the download happened synchronously. Since you want the download to happen in the background, you need to setup a separate method to handle the completion of the download. Right now your video playback code executes just after the download thread is started.
Also, you are acquiring the UI event lock every 1k of download. Since this is a video, I'm assuming a multi-megabyte download, meaning you are acquiring and releasing that lock thousands of times. This doesn't make much sense, in part because the download meter only has 100 different values, so you are mostly updating it with the same value. The easiest fix is to keep track of the last value sent to the model. if it is unchanged, then don't acquire or update the value.
In general, I don't like to acquire the UI lock directly, because there is no queue management. So I use invokeLater for all code that needs to update the UI. This has the nice property that the invokeLater code happens sequentially. You can overrun the queue, as this code would do if you directly change it to invokeLater. To avoid that problem, you have to setup another variable to track whether you've got a progress meter update queued. If so, don't queue any more work.

Related

Vaadin get/set cursor position / selection start/end in Textfield

I know there was in Vaadin7 (8) some methods the get / set the cursor position of the textfield from server side.
I'm using Vaadin Flow v21, but there are no such methods. How can I get/set the cursor position from server side synchronously? To set it seens to work fine using some javascript, but I cannot read the actual cursor position, since it is only going async. How to do it sync?
I try to read like this:
public int getSelectionStart() throws InterruptedException
{
Future<Integer> value = UI.getCurrent().getPage().executeJs(
"return $0.shadowRoot.querySelector('[part=\"value\"]').selectionStart;"
, getElement()).toCompletableFuture(Integer.class);
final int[] val = new int[1];
Thread t = new Thread(() ->
{
Integer result = null;
try
{
result = value.get();
}
catch (Exception e)
{
e.printStackTrace();
}
val[0] = result == null ? 0 : result;
});
t.start();
t.join();
return val[0];
};
But above method gives me exception, that the ongoing UI session request has not been closed yet, so basically it cannot execute the javascript, unless I end the request.
This is how I set cursor position, which seems to work since I don't want to get any return value back, so ending the request is going to execute the script and set the proper cursor position.
public void setSelectionStart(int pos)
{
UI.getCurrent().getPage().executeJs("$0.shadowRoot.querySelector('[part=\"value\"]').setSelectionRange($1, $1);", getElement(), pos);
}
Thanks for any help / suggestion!
I hope the documentation for RPC return values could help here: https://vaadin.com/docs/latest/flow/element-api/client-server-rpc/#return-values

Memory issue when using CGImage.ScreenImage in a loop using Mono Touch

I'm trying to create an app to read QR codes using Monotouch and C# port of Zxing but I'm hitting memory issues. While the app processes captured screen frames the app receives memory warnings and is then shut down. I have removed the call to Zxing to track down where the memory issue stems from and can reproduce the issue with just capturing the screen image in a loop.
Here is the code:
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Threading;
using MonoTouch.UIKit;
using MonoTouch.Foundation;
using MonoTouch.CoreGraphics;
using com.google.zxing;
using com.google.zxing.common;
using System.Collections;
using MonoTouch.AudioToolbox;
using iOS_Client.Utilities;
namespace iOS_Client.Controllers
{
public class CameraOverLayView : UIView
{
private Thread _thread;
private CameraViewController _parentViewController;
private Hashtable hints;
private static com.google.zxing.MultiFormatReader _multiFormatReader = null;
private static RectangleF picFrame = new RectangleF(0, 146, 320, 157);
private static UIImage _theScreenImage = null;
public CameraOverLayView(CameraViewController parentController) : base()
{
Initialize();
_parentViewController = parentController;
}
private void Initialize()
{
}
private bool Worker()
{
Result resultb = null;
if(DeviceHardware.Version == DeviceHardware.HardwareVersion.iPhone4
|| DeviceHardware.Version == DeviceHardware.HardwareVersion.iPhone4S)
{
picFrame = new RectangleF(0, 146*2, 320*2, 157*2);
}
if(hints==null)
{
var list = new ArrayList();
list.Add (com.google.zxing.BarcodeFormat.QR_CODE);
hints = new Hashtable();
hints.Add(com.google.zxing.DecodeHintType.POSSIBLE_FORMATS, list);
hints.Add (com.google.zxing.DecodeHintType.TRY_HARDER, true);
}
if(_multiFormatReader == null)
{
_multiFormatReader = new com.google.zxing.MultiFormatReader();
}
using (var screenImage = CGImage.ScreenImage.WithImageInRect(picFrame))
{
using (_theScreenImage = UIImage.FromImage(screenImage))
{
Bitmap srcbitmap = new System.Drawing.Bitmap(_theScreenImage);
LuminanceSource source = null;
BinaryBitmap bitmap = null;
try {
source = new RGBLuminanceSource(srcbitmap, screenImage.Width, screenImage.Height);
bitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
_multiFormatReader.Hints = hints;
resultb = null;
//_multiFormatReader.decodeWithState(bitmap);
if(resultb != null && resultb.Text!=null)
{
InvokeOnMainThread( () => _parentViewController.BarCodeScanned(resultb));
}
}
catch (ReaderException re)
{
//continue;
}
} catch (Exception ex) {
Console.WriteLine(ex.Message);
}
finally {
if(bitmap!=null)
bitmap = null;
if(source!=null)
source = null;
if(srcbitmap!=null)
{
srcbitmap.Dispose();
srcbitmap = null;
}
}
}
}
return resultb != null;
}
public void StartWorker()
{
if(_thread==null)
{
_thread = new Thread(()=> {
bool result = false;
while (result == false)
{
result = Worker();
Thread.Sleep (67);
}
});
}
_thread.Start();
}
public void StopWorker()
{
if(_thread!=null)
{
_thread.Abort();
_thread = null;
}
//Just in case
_multiFormatReader = null;
hints = null;
}
protected override void Dispose(bool disposing)
{
StopWorker();
base.Dispose(disposing);
}
}
}
Interestingly I took a look at http://blog.reinforce-lab.com/2010/02/monotouchvideocapturinghowto.html to try and see how others were capturing and processing video and this code suffers from the same as mine, quitting after about 40 seconds with memory warnings.
Hopefully the QR codes will be scanned in less than 40 seconds but I'm not sure if the memory ever gets released so the problem may crop up after many codes have been scanned. Either way it should be possible to capture a video feed continuously without memory issues right?
This is somewhat counter-intuitive, but the ScreenImage property will create a new CGImage instance every time you call it, so you must call Dispose on that object as well:
using (var img = CGImage.ScreenImage) {
using (var screenImage = img.WithImageInRect(picFrame))
{
}
}
I will just add the actual solution that worked for me which combined information from previous answers. The code inside the loop looks like:
using (var pool = new NSAutoreleasePool ())
{
using (var img = CGImage.ScreenImage)
{
using (var screenImage = img.WithImageInRect(picFrame))
{
using (_theScreenImage = UIImage.FromImage(screenImage))
{
}
}
}
}
GC.Collect();
The original System.Drawing.Bitmap from zxing.MonoTouch suffered from a lack of Dispose which made it never release the unmanaged memory it allocated.
The more recent one (from your link) does free the unmanaged memory when Dispose is called (it's better). However it creates a bitmap context (in it's constructor) and does not dispose it manually (e.g. with a using). So it relies on the garbage collector (GC) to do it later...
In many cases this is not a big issue since the GC will, eventually, free this context instance and will reclaim the associated memory. However if you're doing this in a loop it's possible you'll run out of (unmanaged) memory before the GC kicks in. That will get you memory warnings and iOS can decide to kill your application (or it could crash by itself).
but I'm not sure if the memory ever gets released
Yes, it should be - but maybe not as fast as you need the memory back. Implementing (and using) IDisposable correctly will solve this.
Either way it should be possible to capture a video feed continuously without memory issues right?
Yes. Make sure you're releasing your memory as soon as possible, e.g. with using (var ...) { }, and ensure the 3rd party code you use does the same.

Integration of twitter posting in Blackberry+IllegalArguementException

i am trying to embed twitter posting feature in my application.
i am using twitter api_me-1.8
i am able to reach the login screen(though most of the text is displayed as boxes- i am guessing that the text is in hindi/tamil as i am in india...), but as soon as i enter my credentials,i get taken to another page with some text in the top in boxes...
and more text in english below that(you can revoke access to any application...) ...then i get an illeagalArguementException after a minute...
i tried to debug the application,
public TwitterUiScreen(String wallMsg) {
System.out.println("Twitter UI BEGINS!");
setTitle("Twitter");
this.wallMsg = wallMsg;
BrowserContentManager browserMngr = new BrowserContentManager(0);
RenderingOptions rendOptions = browserMngr.getRenderingSession()
.getRenderingOptions();
rendOptions.setProperty(RenderingOptions.CORE_OPTIONS_GUID,
RenderingOptions.SHOW_IMAGES_IN_HTML, false);
rendOptions.setProperty(RenderingOptions.CORE_OPTIONS_GUID,
RenderingOptions.ENABLE_EMBEDDED_RICH_CONTENT, true);
rendOptions.setProperty(RenderingOptions.CORE_OPTIONS_GUID,
RenderingOptions.DEFAULT_FONT_FACE, true);
rendOptions.setProperty(RenderingOptions.CORE_OPTIONS_GUID,
RenderingOptions.DEFAULT_CHARSET_VALUE, true);
rendOptions.setProperty(RenderingOptions.CORE_OPTIONS_GUID,
RenderingOptions.JAVASCRIPT_ENABLED, true);
/*
* browserMngr.getRenderingSession().getRenderingOptions().setProperty(
* RenderingOptions.CORE_OPTIONS_GUID,
* RenderingOptions.DEFAULT_FONT_FACE, Font.getDefaultFont());
*/
add(browserMngr);
OAuthDialogWrapper pageWrapper = new BrowserContentManagerOAuthDialogWrapper(browserMngr);
pageWrapper.setConsumerKey(CONSUMER_KEY);
pageWrapper.setConsumerSecret(CONSUMER_SECRET);
pageWrapper.setCallbackUrl(CALLBACK_URL);
pageWrapper.setOAuthListener(this);
pageWrapper.login();
}
i had breakpoints upto the last line, and all of them were hit, with no problems...
but as soon as i logged in, i hit the exception.( i think it was in this page:-
BrowserContentManagerOAuthDialogWrapper.java (version 1.1 : 45.3, super bit)
after which i get to a third screen.
the comment was barely legible- so i thought i might as well add the code over here:
public static final String OAUTH_CALLBACK_SCHEME = "x-oauthflow-twitter";
public static final String OAUTH_CALLBACK_HOST = "callback";
public static final String OAUTH_CALLBACK_URL = OAUTH_CALLBACK_SCHEME+ "://" + OAUTH_CALLBACK_HOST;
private final String CALLBACK_URL = OAUTH_CALLBACK_URL;
i managed to get the source and attach it to the jar file. the exception that the BrowserContentManagerOAuthDialogWrapper.java throws is:: Protocol not found: net.rim.device.cldc.io.x-oauthflow-twitter.Protocol
in this method::
protected void loadUrl(final String url, final byte[] postData,
final Event event) {
new Thread() {
public void run() {
try {
HttpConnection conn = getConnection(url);
//
if (postData != null) {
conn.setRequestMethod(HttpConnection.POST);
conn.setRequestProperty(
"Content-Type",
"application/x-www-form-urlencoded");
conn.setRequestProperty(
"Content-Length", String.valueOf(postData.length));
//
OutputStream out = conn.openOutputStream();
out.write(postData);
out.close();
}
//
browserManager.setContent(
conn, renderingListenerOAuth, event);
} catch (IOException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
}.start();
}
feel like hitting myself.
my clients had told us that the twitter posting was not working...
so i assumed that it did not work.
for some reason, it does not work in the simulator- but seems to work fine on the device.
the clients have assumed that it does not work, as after we try logging in, it takes too long to post, and displays the third screen for about 20 seconds, and they seem to have clicked back early, deciding that posting did not work.
now i need to figure out a way to post a message on the third screen asking the user to wait for the post to be successful.

problem in starting camera?

hie i am using jde 4.5 want to use camera through my app.
i write the code and getting runtime excepetion Pushmodelscreen caaled by non event thread
tell me what the problem in it?
public void start Camera()
{
try {
// Create a player for the Blackberry's camera
Player player= Manager.createPlayer( "capture://video" );
// Set the player to the REALIZED state (see Player javadoc)
player.realize();
// Grab the video control and set it to the current display
_videoControl = (VideoControl)player.getControl( "VideoControl" );
if (_videoControl != null)
{
// Create the video field as a GUI primitive (as opposed to a
// direct video, which can only be used on platforms with
// LCDUI support.)
_videoField = (Field) _videoControl.initDisplayMode (VideoControl.USE_GUI_PRIMITIVE, "net.rim.device.api.ui.Field");
_videoControl.setDisplayFullScreen(true);
_videoControl.setVisible(true);
}
player.start();
if(_videoField!=null)
{
add(_videoField);
}
} catch (Exception e) {
// TODO: handle exception
Dialog.alert(e.getMessage());
}
}
`
thnaks alot
Amit
The code that involved in UI changes should be called from within the UI thread. So most likely some part of your code should be called in a way:
UIApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
// do your UI related staff here
// e.g. push a Screen or call Dialog.alert(), etc.
}
});
Also, you may find this info interesting.

Problem while adding a new value to a hashtable when it is enumerated

`hi
I am doing a simple synchronous socket programming,in which i employed twothreads
one for accepting the client and put the socket object into a collection,other thread will
loop through the collection and send message to each client through the socket object.
the problem is
1.i connect to clients to the server and start send messages
2.now i want to connect a new client,while doing this i cant update the collection and add
a new client to my hashtable.it raises an exception "collection modified .Enumeration operation may not execute"
how to add a NEW value without having problems in a hashtable.
private void Listen()
{
try
{
//lblStatus.Text = "Server Started Listening";
while (true)
{
Socket ReceiveSock = ServerSock.Accept();
//keys.Clear();
ConnectedClients = new ListViewItem();
ConnectedClients.Text = ReceiveSock.RemoteEndPoint.ToString();
ConnectedClients.SubItems.Add("Connected");
ConnectedList.Items.Add(ConnectedClients);
ClientTable.Add(ReceiveSock.RemoteEndPoint.ToString(), ReceiveSock);
//foreach (System.Collections.DictionaryEntry de in ClientTable)
//{
// keys.Add(de.Key.ToString());
//}
//ClientTab.Add(
//keys.Add(
}
//lblStatus.Text = "Client Connected Successfully.";
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void btn_receive_Click(object sender, EventArgs e)
{
Thread receiveThread = new Thread(new ThreadStart(Receive));
receiveThread.IsBackground = true;
receiveThread.Start();
}
private void Receive()
{
while (true)
{
//lblMsg.Text = "";
byte[] Byt = new byte[2048];
//ReceiveSock.Receive(Byt);
lblMsg.Text = Encoding.ASCII.GetString(Byt);
}
}
private void btn_Send_Click(object sender, EventArgs e)
{
Thread SendThread = new Thread(new ThreadStart(SendMsg));
SendThread.IsBackground = true;
SendThread.Start();
}
private void btnlist_Click(object sender, EventArgs e)
{
//Thread ListThread = new Thread(new ThreadStart(Configure));
//ListThread.IsBackground = true;
//ListThread.Start();
}
private void SendMsg()
{
while (true)
{
try
{
foreach (object SockObj in ClientTable.Keys)
{
byte[] Tosend = new byte[2048];
Socket s = (Socket)ClientTable[SockObj];
Tosend = Encoding.ASCII.GetBytes("FirstValue&" + GenerateRandom.Next(6, 10).ToString());
s.Send(Tosend);
//ReceiveSock.Send(Tosend);
Thread.Sleep(300);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
You simply can't modify a Hashtable, Dictionary, List or anything similar while you're iterating over it - whether in the same thread or a different one. There are concurrent collections in .NET 4 which allow this, but I'm assuming you're not using .NET 4. (Out of interest, why are you still using Hashtable rather than a generic Dictionary?)
You also shouldn't be modifying a Hashtable from one thread while reading from it in another thread without any synchronization.
The simplest way to fix this is:
Create a new readonly variable used for locking
Obtain the lock before you add to the Hashtable:
lock (tableLock)
{
ClientTable.Add(ReceiveSock.RemoteEndPoint.ToString(), ReceiveSock);
}
When you want to iterate, create a new copy of the data in the Hashtable within a lock
Iterate over the copy instead of the original table
Do you definitely even need a Hashtable here? It looks to me like a simple List<T> or ArrayList would be okay, where each entry was either the socket or possibly a custom type containing the socket and whatever other information you need. You don't appear to be doing arbitrary lookups on the table.
Yes. Don't do that.
The bigger problem here is unsafe multi-threading.
The most basic "answer" is just to say: use a synchronization lock on the shared object. However this hides a number of important aspects (like understanding what is happening) and isn't a real solution to this problem in my mind.

Resources