Tuesday, July 23, 2013

Getting Size of control in BB10 Cascades API

I was working on update for my Audiobook Reader application for BB10. I wanted to create a custom control like shown below and I required to use AbsoluteLayout to create it.



In this case layouting needs to be done manually and to do that we need to consider width and height of the controls and position controls using those. But unlike Qt Quick, BB10 Cascades controls does not provide access to width, height and x,y properties.

However Cascades API offers LayoutUpdateHandler control, this control gets notification when layout is complete and with notification it offers actual location and size of control and it also store these values in it's layoutFrame property. I used that to find out size of control and did required layouting.

Following code shows how LayoutUpdateHandler can be used to find out size of control.
    Container {
        id: indicators
        layout: AbsoluteLayout {}
        
        touchPropagationMode: TouchPropagationMode.Full
        
        background: Color.DarkGray

        attachedObjects: [
            LayoutUpdateHandler {
                id: handler
            }
        ]

        property alias width: handler.layoutFrame.width;
        property alias height: handler.layoutFrame.height;
    }
Now you can use width and height property to know control's actual size.

Friday, June 21, 2013

Inviting Application Review from Application in BB10 using Cascades API

Most time people leave a review for application when they are unhappy but if they are happy with your app, Chances are high that they will ignore the review. And this might leave impression on App World that your application if not working fine and is of low quality.

To overcome this we might offer user a option to review application from within application and some user might be happy enough to provide review.

BB10 has nice QML Cascades API, which makes the task very easy. Only few lines of code and you can have option to offer review from application.

Following is the code which I am using. You can use InvokeActionItem, with actions property of Page. "sys.appworld" this is invocation target id for App World. And in URI you need to mention your application's ID, which you can find from App World.
Page {
    ...
    actions: [
        ...
        InvokeActionItem {
            title: "Rate Application"
            ActionBar.placement: ActionBarPlacement.InOverflow
            imageSource: "rate.png"
            query {
                invokeTargetId: "sys.appworld"
                invokeActionId: "bb.action.OPEN"
                uri: "appworld://content/20200034"
            }
        }
        ...
    ]
    ...
}


Saturday, June 8, 2013

Using QML Camera and passing image to C++ code

I tried to compile one my application with Qt5. Application was using QML camera and sharing image to C++ code for further processing.

Following is sample code, it works with Qt5 and Qt Multimedia 5.

Lets start with ImageProcessor class, the C++ class which is called from QML to further image processing.

Following is header file for ImageProcessor class, it declares processImage() slot which can be invoked from QML code.
#ifndef IMAGEPROCESSOR_H
#define IMAGEPROCESSOR_H

#include <QObject>

class ImageProcessor : public QObject
{
    Q_OBJECT
public:
    explicit ImageProcessor(QObject *parent = 0);
 
public slots:
    void processImage( const QString& image);   
};
#endif // IMAGEPROCESSOR_H
Following is cpp file for ImageProcessor class. processImage() function retrieves Image from camera image provider. Once we have valid image, we can process it further.
#include "imageprocessor.h"
#include <QtQml/QmlEngine>
#include <QtQml/QmlContext>
#include <QtQuick/QQuickImageProvider>
#include <QDebug>

ImageProcessor::ImageProcessor(QObject *parent)
    : QObject(parent)
{}

void ImageProcessor::processImage( const QString& path)
{
    QUrl imageUrl(path);
    QQmlEngine* engine = QQmlEngine::contextForObject(this)->engine();
    QQmlImageProviderBase* imageProviderBase = engine->imageProvider(
     imageUrl.host());
    QQuickImageProvider* imageProvider = static_cast<QQuickImageProvider>
     (imageProviderBase);
    
    QSize imageSize;
    QString imageId = imageUrl.path().remove(0,1);
    QImage image = imageProvider->requestImage(imageId, &imageSize, imageSize);
    if( !image.isNull()) {
        //process image
    }
}
Now we need to register ImageProcessor class with QML. so that we can use it from QML code. This can be done by using qmlRegisterType global function.
#include  <QtGui/QGuiApplication>
#include  <QQmlEngine>
#include  <QQmlComponent>
#include  <QtQuick/QQuickView>

#include "imageprocessor.h"

int main(int argc, char *argv[])
{
    qmlRegisterType<ImageProcessor>("ImageProcessor", 1, 0, "ImageProcessor");

    QGuiApplication app(argc, argv);

    QQuickView view;

    QObject::connect(view.engine(),SIGNAL(quit()),&app,SLOT(quit()));    
    view.setSource(QUrl::fromLocalFile("qml/main.qml"));
    view.show();

    return app.exec();
}
That's all from C++ side, QML code is event easier. Following how you can use ImageProcess class from QML code.
import QtQuick 2.0
import QtMultimedia 5.0
import ImageProcessor 1.0

Rectangle {
    width: 360
    height: 360

    //shows live preview from camera
    VideoOutput {
        source: camera
        anchors.fill: parent
        focus : visible
    }

    //shows captured image
    Image {
        id: photoPreview
        anchors.fill: parent
        fillMode: Image.PreserveAspectFit
    }

    Camera {
        id: camera
        imageProcessing.whiteBalanceMode: CameraImageProcessing.WhiteBalanceFlash
        captureMode: Camera.CaptureStillImage

        exposure {
            exposureCompensation: -1.0
            exposureMode: Camera.ExposurePortrait
        }

        flash.mode: Camera.FlashRedEyeReduction

        imageCapture {
            onImageCaptured: {
                photoPreview.source = preview
                imageProcessor.processImage(preview);
            }
        }
    }

    MouseArea{
        anchors.fill: parent
        onClicked: {
            camera.imageCapture.capture();
        }
    }

    //image processor for further image processing
    ImageProcessor{
        id: imageProcessor
    }
}

Thursday, June 6, 2013

VMWare Workstation 9.0.1 on Ubuntu 13.04

I recently upgraded my Ubuntu machine to Ubuntu 13.04.  Update went smoothly and all my usual application worked fine. But after some time I needed to use VMWare workstation and I realized its not working any more.

I got following error.


This is caused by some header location changes. This can be resolved by following command.

sudo ln -s /usr/src/linux-headers-$(uname -r)/include/generated/uapi/linux/version.h /usr/src/linux-headers-$(uname -r)/include/linux/version.h

Once this is done, you will need to compile and install VMware modules. When I pressed install button, nothing was happening.


To check I tried to compile modules from command line.

sudo vmware-modconfig --console --install-all

But this was throwing many compilation error, anyway I found this script which make above process easier, It make link for kernel header to expected location and then build VMWare modules. You can find more details about script here.

This script seems to be working but still there was some error in driver.c file. I was getting following errors.

make[1]: Entering directory `/usr/src/linux-headers-3.8.0-23-generic'
  CC [M]  /tmp/modconfig-IBc3U5/vmci-only/linux/driver.o
  CC [M]  /tmp/modconfig-IBc3U5/vmci-only/linux/vmciKernelIf.o
  CC [M]  /tmp/modconfig-IBc3U5/vmci-only/common/vmciContext.o
  CC [M]  /tmp/modconfig-IBc3U5/vmci-only/common/vmciDatagram.o
/tmp/modconfig-IBc3U5/vmci-only/linux/driver.c:1754:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘vmci_probe_device’
/tmp/modconfig-IBc3U5/vmci-only/linux/driver.c:1982:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘vmci_remove_device’
/tmp/modconfig-IBc3U5/vmci-only/linux/driver.c:119:12: warning: ‘vmci_probe_device’ used but never defined [enabled by default]
/tmp/modconfig-IBc3U5/vmci-only/linux/driver.c:121:13: warning: ‘vmci_remove_device’ used but never defined [enabled by default]
/tmp/modconfig-IBc3U5/vmci-only/linux/driver.c:2063:1: warning: ‘vmci_interrupt’ defined but not used [-Wunused-function]
/tmp/modconfig-IBc3U5/vmci-only/linux/driver.c:2137:1: warning: ‘vmci_interrupt_bm’ defined but not used [-Wunused-function]
/tmp/modconfig-IBc3U5/vmci-only/linux/driver.c:1717:1: warning: ‘vmci_enable_msix’ defined but not used [-Wunused-function]
make[2]: *** [/tmp/modconfig-IBc3U5/vmci-only/linux/driver.o] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [_module_/tmp/modconfig-IBc3U5/vmci-only] Error 2
make[1]: Leaving directory `/usr/src/linux-headers-3.8.0-23-generic'

To resolve those error you will need this kernel patch, this patch is for 3.8.0 kernel, it might not work for you. You can find more information about this patch here. To apply patch follow following steps.

1. cd /usr/lib/vmware/modules/source
2. tar -xf vmci.tar
3. cd vmci-only
4. patch -p1 < 'patchfile'
5. cd ..
6. tar -cf vmci.tar vmci-only/
7. vmware-modconfig --console --install-all
8. rm -rf vmci-only/

Once you applied above patch, VMWare module should compile fine. I ran above script, which link kernel header and build VMware module, and then I was able to use VMWare workstation.

Still there was one last hurdle, When I tried to run my virtual machine, it asked for serial number, But when I tried to enter serial number, Dialog for entering serial number was not getting launched.

To resolve those I need to supply serial number from terminal, using following command.

/usr/lib/vmware/bin/vmware-vmx --new-sn 123-123-123-123...123

Finally, I was able to use my virtual machine. I guess if you rely on virtual machine heavily, then its better to avoid Ubuntu/Kernel upgrade.

Sunday, May 26, 2013

Converting APK to BAR and deploying it to BB10 device

As you might know BB10 device support Android application. But to install Android application on BB10, first you need to convert .apk file to .bar file.

I already have install BB10 NDK (Native Development Kit ), so I did not struggled with installing certificate file and setup the signer. BB10 NDK installer and IDE did that for me.

You will also need android sdk installed on your pc, before you begin. You can find detailed instruction here at BlackBerry Development site.

Following are few steps that I often use to convert APK to BAR file.

1) export ANDOID_HOME varible

export ANDROID_HOME=~/android_sdk/sdk/

2) Verify if APK file does not you unsupported APIs.

 ./apk2barVerifier ./ANDROID_APPLICATION.apk 

3) If your APK does not use unsupported APIs then you can go ahead and covert APK to BAR to test on your device.

./apk2bar ./ANDROID_APPLICATION.apk -d DEBUG_TOKEN_FILE 

4) Install BAR file to development device.

Following will deploy all BAR files under test folder to device.I find this method easier.

./batchbar-deploy ~/Desktop/test 169.254.0.1 DEVICE_DEVELOPMENT_PASSWORD

Or you can deply individual BAR file using following command.

 ./blackberry-deploy -installapp -package ./BAR_FILE.bar -device 169.254.0.1 -password DEVICE_DEVELOPMENT_PASSWORD

Once testing is done, you can use blackberry-signer command to sign BAR file and publish it on App World. But I did not tried it my self. I just wanted to install one android app on my BB10 and my device is always on development mode so I just used BAR files with Debug token.