Is there a method for creating a log file using a blackberry api ?
Something like log4j ?
I'd like to save this log file on pc running the emulator, is this possible ?
At Antair, during development of our BlackBerry applications, we often include a debug console in the dev builds of our apps.
With the debug console, all debug output hits the output screen when the dev build is running in the simulator, and when the dev build runs on a physical test device, the debug output is automatically persisted and is available to view on a dedicated screen that can be pulled up via a menu option or button. With a little code modification, you can easily have the debug log be rerouted to a file, emailed or sent over a network connection.
The code below is a stripped-down version of the debug console we use at our company.
Using the console is easy. Include the code in your project, fill out the PERSISTENCE_GUID for your application, set the TAGID string to identify your application name in the debug logs, and when you want to output a debug statement, simply call Debug.print(”Something happened here…“);
Each line of the debug output, both in the output window when running in a simulator, and in the debug console screen when viewed on a device, will contain your debug message, the thread number on which the call was made (useful for thread/ui debugging), and the date/time of the log statement, with a millisecond timestamp for performance profiling.
To view the debug console on a real device, simple put in a call to pushScreen(new AntairLogScreen()). The screen has a built-in menu item to clear the persisted log messages, and will dismiss itself like a regular application screen.
If you’re running the RIM compiler preprocessor to switch between development, QA, and production builds, you can simply put in a call to set Debug.ENABLED = false for everything but the development builds, and the debug console will be there when you need to debug and go away quietly when you don’t need it.
The code is below.
// ---------------------------------------------------------------------------
// Antair Debug Log (for the BlackBerry API)
// http://www.antair.com
// ---------------------------------------------------------------------------
package com.antair.examples.debug;
import net.rim.device.api.i18n.SimpleDateFormat;
import java.util.Date;
import net.rim.device.api.collection.util.BigVector;
import net.rim.device.api.system.PersistentObject;
import net.rim.device.api.system.PersistentStore;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.component.RichTextField;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.util.Persistable;
final class Debug implements Persistable
{
final static boolean ENABLED = true;
final static String TAGID = "MY_PROJECT";
final static long PERSISTENCE_GUID = /* YOUR OWN PERSISTENCE GUID */;
private BigVector _messages = new BigVector();
static String print(String str)
{
if ( Debug.ENABLED )
{
StringBuffer sb = new StringBuffer();
sb.append(TAGID);
sb.append("\n");
sb.append(Thread.currentThread().toString());
sb.append("\n");
sb.append(new SimpleDateFormat("MM/dd/yy HH:mm:ss:SSS").format(
new Date()));
sb.append("\n");
sb.append(str); sb.append("\n");
str = sb.toString();
System.out.println(str);
System.out.flush();
Debug d = load();
d._messages.addElement(str);
save(d);
}
return str;
}
static BigVector getPersistedMessages()
{
return load()._messages;
}
static void clearPersistedMessages()
{
save(new Debug());
}
private static Debug load()
{
Debug d = null;
try
{
PersistentObject po =
PersistentStore.getPersistentObject(Debug.PERSISTENCE_GUID);
synchronized(po)
{
Object obj = po.getContents();
d = (obj == null) ? new Debug() : (Debug)obj;
}
}
catch ( Exception e )
{
d = new Debug();
}
return d;
}
private static void save(Debug d)
{
try
{
PersistentObject po =
PersistentStore.getPersistentObject(Debug.PERSISTENCE_GUID);
synchronized(po)
{
po.setContents(d);
po.commit();
}
}
catch ( Exception e )
{
}
}
}
final class ClearAntairLogScreenMenuItem extends MenuItem
{
ClearAntairLogScreenMenuItem(int position)
{
super("Clear Log", position, 0);
}
public void run()
{
Debug.clearPersistedMessages();
}
}
final class AntairLogScreen extends MainScreen
{
AntairLogScreen()
{
super(MainScreen.DEFAULT_CLOSE|MainScreen.DEFAULT_MENU);
StringBuffer text = new StringBuffer();
BigVector logItems = Debug.getPersistedMessages();
for ( int i = 0 ; i < logItems.size() ; ++i )
{
text.append((String)logItems.elementAt(i) + "\n");
}
add(new RichTextField(text.toString()));
}
protected void makeMenu ( Menu menu, int instance )
{
menu.add(new ClearAntairLogScreenMenuItem(100000));
}
}
BlackBerry has its own log facility - EventLogger, but I find it to be ugly. You can write to EventLogger, but you can not view it as easily as you might with other logs or for example you can not extract the content programmatically to send over http/email.
I think it is much more comfortable to use your custom logger class that writes log entries directly to a log file on the SD card. Since the SD card on the emulator is a folder on your PC, you can easily monitor the app with any PC log viewer in real time.
Also as a bonus with such approach you can have some code to send the log over http/email. Such logging on a real device will slow down the app significantly, so it should not be normally used in production, but your app could have such option (to enable the debug mose) so it'll allow to know the reason which otherwise would remain unknown.
Related
I have a fundamental problem that I can not really understand where the problem comes from.
I am designing a project by xamarin.android webview.
Now I need to run a Java function in Web View and check the return value in a if function.
I searched all the websites and in all of them I got the following code:
In Main Activity Class:
public class MainActivity : AppCompatActivity
{
WebView web_view;
.
.
.
Define web_view public in class
In OnCreate :
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.activity_main);
web_view = FindViewById<WebView>(Resource.Id.webview);
web_view.Settings.JavaScriptEnabled = true;
web_view.Settings.BuiltInZoomControls = true;
web_view.Settings.AllowContentAccess = true;
web_view.SetWebViewClient(new HelloWebViewClient());
web_view.LoadUrl("https://www.example.com");
}
In Back Key Press:
public override bool OnKeyDown(Android.Views.Keycode keyCode, Android.Views.KeyEvent e)
{
if (keyCode == Keycode.Back)
{
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat)
{
JavascriptResult jsr = new JavascriptResult();
string strjs = "closePackageDetails();";
web_view.EvaluateJavascript(strjs, jsr);
string rrr = jsr.strResult;
Toast.MakeText(this, "message send:" + rrr, ToastLength.Long).Show();
}
else
{
Toast.MakeText(this, "android version less 4.4" , ToastLength.Long).Show();
}
}
}
On JavascriptResult Class (separate on C# Class Palaced in MainActivity in Root directory)
namespace webviewapp
{
class JavascriptResult : Java.Lang.Object, IValueCallback
{
public string strResult;
public void OnReceiveValue(Java.Lang.Object result)
{
Toast.MakeText(Android.App.Application.Context, "رسیدن نتیجه احضار شد", ToastLength.Long);
strResult = ((Java.Lang.String)result).ToString();
}
}
}
<>
Everything looks right and the program is debugged without error and the APK file is created successfully.
After installing the program on the mobile phone and running it, the web page is loaded and everything looks good.
By touching the back button, the JavaScript function is executed correctly and the result is visible in Web View. But the result, which is a boolean value, is not returned.
In fact, the OnReceiveValue procedure does not work.
The variable 'rrr' always displays an null value.
Where it went wrong really puzzled me?
It is happening because the callback is executed later than the next line ,so the variable 'rrr' is always null.
Add the breakpoint at OnReceiveValue and the line string rrr = jsr.strResult; to check it .
Just do the next thing directly in the method OnReceiveValue in the callback class.
I combined learnings from two different sources to detect open windows using UIAutomation and to move the windows:
Detect the opening of a new window in C#
Move a UI Automation Element
I can get practically every app window to move (Win32 apps and UWP apps). Except for the Microsoft Edge browser window!
QUESTION: Does anyone know how to use UIAutomation to move the Edge window? Does anyone know what is special about the Edge browser that prevents it from adhering to Microsoft's own UIAutomation library?
Here's my full console app code (required: Add references to UIAutomationClient and UIAutomationTypes):
using System;
using System.Threading;
using System.Windows.Automation;
namespace UiAutomationTest
{
class Program
{
static void Main(string[] args)
{
Automation.AddAutomationEventHandler(eventId: WindowPattern.WindowOpenedEvent, element: AutomationElement.RootElement, scope: TreeScope.Children, eventHandler: OnWindowOpened);
Console.ReadLine();
Automation.RemoveAllEventHandlers();
}
private static void OnWindowOpened(object sender, AutomationEventArgs e)
{
try
{
var element = sender as AutomationElement;
if (element != null)
{
var hWnd = new IntPtr(element.Current.NativeWindowHandle);
Console.WriteLine($"Opened: {element.Current.Name} (Pid:{element.Current.ProcessId}),hWnd:{Convert.ToInt32(hWnd.ToString())}");
var _windowPattern = GetControlPattern(element, WindowPattern.Pattern) as WindowPattern;
if (_windowPattern == null)
{
Console.WriteLine("WindowPattern is null! Aborting.");
return;
}
if (false == _windowPattern.WaitForInputIdle(10000))
{
Feedback("Object not responding in a timely manner.");
return;
}
Console.WriteLine("Window is ready for input");
var _transformPattern = GetControlPattern(element, TransformPattern.Pattern) as TransformPattern;
if (_transformPattern == null)
{
Console.WriteLine("TransformPattern is null! Aborting.");
return;
}
// Is the TransformPattern object moveable?
if (_transformPattern.Current.CanMove)
{
Console.WriteLine("Waiting 3 seconds before move...");
// Wait a bit
Thread.Sleep(3000);
// Move element
_transformPattern.Move(250, 500);
Console.WriteLine("Window was moved!");
}
else
{
Feedback("Window is not moveable.");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"{ex.GetType()}: {ex.Message}\n{ex.StackTrace}");
}
}
/// <summary>
/// Gets a specified control pattern.
/// </summary>
/// <param name="ae">The automation element we want to obtain the control pattern from.</param>
/// <param name="ap">The control pattern of interest.</param>
/// <returns>A ControlPattern object.</returns>
private static object GetControlPattern(AutomationElement ae, AutomationPattern ap)
{
if (false == ae.TryGetCurrentPattern(ap, out object oPattern))
{
Feedback("Object does not support the " + ap.ProgrammaticName + " Pattern");
return null;
}
Feedback("Object supports the " + ap.ProgrammaticName + " Pattern.");
return oPattern;
}
private static void Feedback(string message)
{
Console.WriteLine(message);
}
}
}
Here's a video showing that I can open Internet Explorer and move it, Chrome and move it, but Edge won't move!
CantMoveEdgeWindow.mp4
System Details:
Windows 10 1809
Visual Studio 2019 16.7
.NET Framework 4.7.2 C# Console App
Lastly, I have even tried using old school Win32 APIs such as EnumWindows, MoveWindow, SetWindowPlacement, and SetWindowPos. The Edge browser appears to be housed inside of an ApplicationFrameHost.exe process window. When I try to move the window, I get the same result as using the UIAutomation libraries: It "says" it passed, but the window doesn't actually move!
I am trying to scan QR code with my code. My code is running fine with 5.0(Bold) and 7.1(Torch) OS phones. It is running fine with 7.1 and 5.0. but giving problem while running with 6.0 OS(Bold 9700). The problem is - "While trying to scan QR code, app scans the QR code but camera screen doesn't pop and it remains at the front. Event it is not able to hide by using Esc key". please help me to resolve the issue with os6.
Edit:
Code while opening camera screen for QR code scan:
Hashtable hints = new Hashtable();
// The first thing going in is a list of formats. We could look for
// more than one at a time, but it's much slower.
Vector formats = new Vector();
formats.addElement(BarcodeFormat.QR_CODE);
hints.put(DecodeHintType.POSSIBLE_FORMATS, formats);
// We will also use the "TRY_HARDER" flag to make sure we get an
// accurate scan
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
// We create a new decoder using those hints
BarcodeDecoder decoder = new BarcodeDecoder(hints);
// Finally we can create the actual scanner with a decoder and a
// listener that will handle the data stored in the QR code. We put
// that in our view screen to handle the display.
try {
_scanner = new BarcodeScanner(decoder, new LeadQRcodeDecoderListener());
_QRcodeScreen = new LeadQRcodeScannerViewScreen(_scanner);
// If we get here, all the QR code scanning infrastructure should be set
// up, so all we have to do is start the scan and display the viewfinder
_scanner.startScan();
UiApplication.getUiApplication().pushScreen(_QRcodeScreen);
}
catch (Exception e) {
e.printStackTrace();
return;
}
code for closing screen is:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().popScreen(_QRcodeScreen);
}
});
I am calling this code after scanning of QR code.
This is a problem with OS6 in some devices that has been asked before on this site. Last one was two days ago:
Blackberry OS6 camera wont shut down after capture
AFAIK there's no API to close the camera app, so it has to be done with key injection hacks, that are tricky because they need accurate timing and as CPUs are different in some models, and also because the camera app has a different design in some OSes.
So either you use JSR135 and use a renamed Zxing package to provide a camera view contained in your app, or just follow your approach but instead of closing the camera app you just bring to foreground your own app.
I have solved my same issue for os 6. After scanning of QR code, close all player and scanner connection.
You can use-
if (_scanner != null && _scanner.getPlayer() != null) {
_scanner.getPlayer().close();
}
It is helpful to me.
This will definitely help you.
here is my code , it's working perfectly in OS 6.0 device 9830
/**
* First Invoke the QR Scanner
*/
ViewFinderScreen _viewFinderScreen =
new ViewFinderScreen(ShoopingCartScreen.this); // ShoopingCartScreen.this Current Screen Object
UiApplication.getUiApplication().pushScreen(_viewFinderScreen);
package com.application.qrScanner;
import java.util.Hashtable;
import java.util.Vector;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.control.VideoControl;
import net.rim.device.api.barcodelib.BarcodeDecoder;
import net.rim.device.api.barcodelib.BarcodeDecoderListener;
import net.rim.device.api.barcodelib.BarcodeScanner;
import net.rim.device.api.io.Base64InputStream;
import net.rim.device.api.io.http.HttpDateParser;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.Keypad;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.container.MainScreen;
import com.application.data.ShoopingCartObj;
import com.application.global.Global;
import com.application.log.Log;
import com.application.main.MessageScreen;
import com.application.main.orderDetail.orderSection.InputPopUpScreen;
import com.application.main.shoopingSection.ShoopingCartScreen;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
public class ViewFinderScreen extends MainScreen
{
private BarcodeScanner _scanner;
private short _frequency = 1046;
private short _duration = 200;
private int _volume = 100;
private VideoControl vc;
private ButtonField _btnCancel;
private ShoopingCartScreen _shoopingCartScreen;
/**
* Creates a new ViewFinderScreen object
*/
public ViewFinderScreen(ShoopingCartScreen _shoopingCartScreen)
{
this._shoopingCartScreen = _shoopingCartScreen;
_btnCancel = new ButtonField("Cancel" , ButtonField.USE_ALL_WIDTH)
{
protected boolean navigationClick(int status, int time)
{
fieldChangeNotify(1);
return true;
}
};
_btnCancel.setChangeListener(new FieldChangeListener()
{
public void fieldChanged(Field field, int context)
{
stopScan();
UiApplication.getUiApplication().popScreen(ViewFinderScreen.this);
}
});
// Initialize Hashtable used to inform the scanner how to
// recognize the QR code format.
Hashtable hints = new Hashtable();
Vector formats = new Vector(1);
formats.addElement(BarcodeFormat.QR_CODE);
hints.put(DecodeHintType.POSSIBLE_FORMATS, formats);
// Initialize the BarcodeDecoder
BarcodeDecoder decoder = new BarcodeDecoder(hints);
// Create a custom instance of a BarcodeDecoderListener to pop the
// screen and display results when a QR code is recognized.
BarcodeDecoderListener decoderListener = new BarcodeDecoderListener()
{
/**
* #see BarcodeDecoderListener#barcodeDecoded(String)
*/
public void barcodeDecoded(String rawText)
{
try {
String encoded = rawText;
byte[] decoded = Base64InputStream.decode( encoded );
rawText = new String(decoded);
System.out.println( new String( decoded ) );
}
catch (Throwable t) {
System.out.println( "Unable to decode string: " + t.getMessage() );
}
displayMessage(rawText);
ViewFinderScreen.this. _shoopingCartScreen.beep();
}
};
try
{
// Initialize the BarcodeScanner object and add the associated
// view finder.
_scanner = new BarcodeScanner(decoder, decoderListener);
vc = _scanner.getVideoControl();
vc.setDisplayFullScreen(true);
add(_scanner.getViewfinder());
setStatus(_btnCancel);
}
catch(Exception e)
{
displayMessage("Initilize Scanner: " + e.getMessage());
}
startScan();
}
/**
* Informs the BarcodeScanner that it should begin scanning for QR Codes
*/
public void startScan()
{
try
{
_scanner.startScan();
}
catch(MediaException me)
{
displayMessage(" Start Scan Error: " + me.getMessage());
}
}
public void stopScan()
{
try
{
Player p = _scanner.getPlayer() ;
if(p != null)
{
p.stop();
p.deallocate();
p.close();
}
}
catch (Exception e)
{
MessageScreen.msgDialog("Exception in Stop Scanning "+e.toString());
}
}
/**
* Pops the ViewFinderScreen and displays text on the main screen
*
* #param text Text to display on the screen
*/
private void displayMessage(final String text)
{
Log.d("QR Code String ", text);
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
stopScan();
}
});
}
protected boolean keyDown(int keycode, int time)
{
if (Keypad.key(keycode) == Keypad.KEY_ESCAPE)
{
stopScan();
return true;
}
return super.keyDown(keycode, time);
}
}
I am developing a web scraper using JavaFX webview. For the scraping purpose, I don't need to have the images to be loaded. When the page is being loaded, Webkit spawns lots of UrlLoader thread. So I think it's better to have the images disabled, so I will save lots of system resources. Does anyone know how to disable automatic image loading in Webview?
Solution Approach
Define your own protocol handler for http and filter out anything with an image mime type or content.
URL.setURLStreamHandlerFactory(new HandlerFactory());
Sample Code
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.web.*;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.*;
public class LynxView extends Application {
private static final String BLANK_IMAGE_LOC =
"https://upload.wikimedia.org/wikipedia/commons/c/ce/Transparent.gif";
public static final String WEBSITE_LOC =
"http://fxexperience.com";
public static final String IMAGE_MIME_TYPE_PREFIX =
"image/";
#Override
public void start(Stage stage) throws Exception {
WebView webView = new WebView();
WebEngine engine = webView.getEngine();
engine.load(WEBSITE_LOC);
stage.setScene(new Scene(new StackPane(webView)));
stage.show();
}
public static void main(String[] args) throws IOException {
URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
#Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("http".equals(protocol)) {
return new sun.net.www.protocol.http.Handler() {
#Override
protected URLConnection openConnection(URL url, Proxy proxy) throws IOException {
String[] fileParts = url.getFile().split("\\?");
String contentType = URLConnection.guessContentTypeFromName(fileParts[0]);
// this small hack is required because, weirdly, svg is not picked up by guessContentTypeFromName
// because, for Java 8, svg is not in $JAVA_HOME/lib/content-types.properties
if (fileParts[0].endsWith(".svg")) {
contentType = "image/svg";
}
System.out.println(url.getFile() + " : " + contentType);
if ((contentType != null && contentType.startsWith(IMAGE_MIME_TYPE_PREFIX))) {
return new URL(BLANK_IMAGE_LOC).openConnection();
} else {
return super.openConnection(url, proxy);
}
}
};
}
return null;
}
});
Application.launch();
}
}
Sample Notes
The sample uses concepts from:
Getting A File's Mime Type In Java
The sample only probes the filename to determine the content type and not the input stream attached to the url. Though probing the input stream would be a more accurate way to determine if the resource the url is connected to is actually an image or not, it is slightly less efficient to probe the stream, so the solution presented trades accuracy for efficiency.
The provided solution only demonstrates locations served by a http protocol, and not locations served by a https protocol.
The provided solution uses a sun.net.www.protocol.http.Handler class which may not be publicly visible in Java 9, (so the solution might not work for Java 9).
The urlStreamHandlerFactory is a global setting for the JVM, so once it is set, it will stay that way (e.g. all images for any java.net.URL connections will be ignored).
The sample solution returns a blank (transparent) image, which it loads over the net. For efficiency, the image could be loaded as a resource from the classpath instead of over the net.
You could return a null connection rather a than a connection to a blank image, if you do so, the web view code will start reporting null pointer exceptions to the console because it is not getting the url connection it expects, and will replace all images with an x image to show that the image is missing (I wouldn't really recommend an approach which returned a null connection).
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("http".equals(protocol)) {
return new URLFortuneHandler();
}
else return null;
}
}
public class URLFortuneHandler extends sun.net.www.protocol.http.Handler {
protected URLConnection openConnection(URL url) throws IOException {
String file = url.getFile();
int mid= file.lastIndexOf(".");
String ext = file.substring(mid+1,file.length());
if ("jpg".equals(ext) || "png".equals(ext))
return somethinghere;
else
return super.openConnection(url);
}
}
I am trying to create a background app which will run at system startup. When I run it manually (from the ribbon), the screen appears but when I run the app after making it a startup app (Auto-run on startup option in descriptor), nothing appears on screen. I am trying the following code;
public class AppClass extends UiApplication {
public static void main(String[] args) {
AppClass theApp = new AppClass();
theApp.enterEventDispatcher();
}
public AppClass() {
pushScreen(new AppScreen());
}
}
And this is the screen class;
public final class AppScreen extends MainScreen {
private LabelField label;
public AppScreen() {
setTitle("AppTitle");
label = new LabelField();
label.setText("Ready.");
add(label);
}
}
I am expecting that its a UI app so its screen should be visible no matter if is auto-run at startup or run manually. If I need to do something to make it work as expected, please guide me about it, I am new to BlackBerry development.
I am developing in the following environment;
BlackBerry JDE Eclipse Plugin 1.5.0
BlackBerry OS 4.5
Auto start applications are run before the OS has completed booting so there isn't any support for the user interface. I suspect your application is being launched but failing on some UI call. The documented way to write an application that is to auto run and run from the home screen is to provide an alternated entry point for the auto run with arguments that tell the program it has been auto run. Then use the API to wait until the OS is ready for UI applications.
public class AppClass extends UiApplication {
public static void main(String[] args) {
if (args.length > 0 && args[0].equals("auto-run")) {
// auto start, wait for OS
while (ApplicationManager.getApplicationManager().inStartup()) {
Thread.sleep(10000);
}
/*
** Do auto-run UI stuff here
*/
} else {
AppClass theApp = new AppClass();
theApp.enterEventDispatcher();
}
}
public AppClass() {
pushScreen(new AppScreen());
}
}
Call getApplication().requestForeground(); from the constructor of your AppScreen class so that your screen will be visible.
public final class AppScreen extends MainScreen {
private LabelField label;
public AppScreen() {
setTitle("AppTitle");
label = new LabelField();
label.setText("Ready.");
add(label);
getApplication().requestForeground();
}
}
Once the app is running in background, we have to bring it to foreground explicitly to show UI element and that is what we are doing here.