Background Application unable to display UI when receive push notification

770 views Asked by At

Here is my full push notification listener.

public class MyApp extends UiApplication {
    public static void main(String[] args) {
        PushAgent pa = new PushAgent();
        pa.enterEventDispatcher();
    }
}

Is this class extended correctly?

public class PushAgent extends Application {
private static final String PUSH_PORT = "32023";
private static final String BPAS_URL = "http://pushapi.eval.blackberry.com";
private static final String APP_ID = "2727-c55087eR3001rr475448i013212a56shss2";
private static final String CONNECTION_SUFFIX = ";deviceside=false;ConnectionType=mds-public";

public static final long ID = 0x749cb23a75c60e2dL;

private MessageReadingThread messageReadingThread;

public PushAgent() {
    if (!CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_BIS_B)) {
        return;
    }
    if (DeviceInfo.isSimulator()) {
        return;
    }
    messageReadingThread = new MessageReadingThread();
    messageReadingThread.start();
    registerBpas();
}

private static class MessageReadingThread extends Thread {

    private boolean running;
    private ServerSocketConnection socket;
    private HttpServerConnection conn;
    private InputStream inputStream;
    private PushInputStream pushInputStream;

    public MessageReadingThread() {
        this.running = true;
    }

    public void run() {
        String url = "http://:" + PUSH_PORT + CONNECTION_SUFFIX;

        try {
            socket = (ServerSocketConnection) Connector.open(url);
        } catch (IOException ex) {
        }

        while (running) {
            try {
                Object o = socket.acceptAndOpen();
                conn = (HttpServerConnection) o;
                inputStream = conn.openInputStream();
                pushInputStream = new MDSPushInputStream(conn, inputStream);
                PushMessageReader.process(pushInputStream, conn);
            } catch (Exception e) {
                if (running) {
                    running = false;
                }
            } finally {
                close(conn, pushInputStream, null);
            }
        }
    }
}

public static void close(Connection conn, InputStream is, OutputStream os) {
    if (os != null) {
        try {
            os.close();
        } catch (IOException e) {
        }
    }
    if (is != null) {
        try {
            is.close();
        } catch (IOException e) {
        }
    }
    if (conn != null) {
        try {
            conn.close();
        } catch (IOException e) {
        }
    }
}

private String formRegisterRequest(String bpasUrl, String appId,
        String token) {
    StringBuffer sb = new StringBuffer(bpasUrl);
    sb.append("/mss/PD_subReg?");
    sb.append("serviceid=").append(appId);
    sb.append("&osversion=").append(DeviceInfo.getSoftwareVersion());
    sb.append("&model=").append(DeviceInfo.getDeviceName());
    if (token != null && token.length() > 0) {
        sb.append("&").append(token);
    }
    return sb.toString();
}

private void registerBpas() {
    final String registerUrl = formRegisterRequest(BPAS_URL, APP_ID, null)
            + CONNECTION_SUFFIX;
    Object theSource = new Object() {
        public String toString() {
            return "Oriental Daily";
        }
    };

    NotificationsManager.registerSource(ID, theSource,
            NotificationsConstants.IMPORTANT);

    new Thread() {
        public void run() {
            try {
                HttpConnection httpConnection = (HttpConnection) Connector
                        .open(registerUrl);
                InputStream is = httpConnection.openInputStream();
                String response = new String(IOUtilities.streamToBytes(is));
                close(httpConnection, is, null);

                String nextUrl = formRegisterRequest(BPAS_URL, APP_ID,
                        response) + CONNECTION_SUFFIX;
                HttpConnection nextHttpConnection = (HttpConnection) Connector
                        .open(nextUrl);
                InputStream nextInputStream = nextHttpConnection
                        .openInputStream();
                response = new String(
                        IOUtilities.streamToBytes(nextInputStream));
                close(nextHttpConnection, is, null);
            } catch (IOException e) {
            }
        }
    }.start();
}
}
}

This is the process;

public class PushMessageReader {
private static final String MESSAGE_ID_HEADER = "Push-Message-ID";
private static final String MESSAGE_TYPE_TEXT = "text";
private static final String MESSAGE_TYPE_IMAGE = "image";

private static final int MESSAGE_ID_HISTORY_LENGTH = 10;
private static String[] messageIdHistory = new String[MESSAGE_ID_HISTORY_LENGTH];
private static byte historyIndex;

private static byte[] buffer = new byte[15 * 1024];
private static byte[] imageBuffer = new byte[10 * 1024];

public static final long ID = 0x749cb23a75c60e2dL;
public static Bitmap popup = Bitmap.getBitmapResource("icon_24.png");

private PushMessageReader() {
}

public static void process(PushInputStream pis, Connection conn) {
    try {
        HttpServerConnection httpConn;

        if (conn instanceof HttpServerConnection) {
            httpConn = (HttpServerConnection) conn;
        } else {
            throw new IllegalArgumentException(
                    "Can not process non-http pushes, expected HttpServerConnection but have "
                            + conn.getClass().getName());
        }

        String msgId = httpConn.getHeaderField(MESSAGE_ID_HEADER);
        String msgType = httpConn.getType();
        String encoding = httpConn.getEncoding();

        if (!alreadyReceived(msgId)) {
            byte[] binaryData;

            if (msgId == null) {
                msgId = String.valueOf(System.currentTimeMillis());
            }

            if (msgType.indexOf(MESSAGE_TYPE_TEXT) >= 0) {
                int size = pis.read(buffer);
                binaryData = new byte[size];
                System.arraycopy(buffer, 0, binaryData, 0, size);

                NotificationsManager.triggerImmediateEvent(ID, 0, null,
                        null);
                processTextMessage(buffer);
            } else if (msgType.indexOf(MESSAGE_TYPE_IMAGE) >= 0) {
                int size = pis.read(buffer);

                if (encoding != null && encoding.equalsIgnoreCase("base64")) {
                    Base64InputStream bis = new Base64InputStream(
                            new ByteArrayInputStream(buffer, 0, size));
                    size = bis.read(imageBuffer);
                }

                binaryData = new byte[size];
                System.arraycopy(buffer, 0, binaryData, 0, size);
            }
        }
        pis.accept();
    } catch (Exception e) {

    } finally {
        PushAgent.close(conn, pis, null);
    }
}

private static boolean alreadyReceived(String id) {
    if (id == null) {
        return false;
    }

    if (Arrays.contains(messageIdHistory, id)) {
        return true;
    }

    messageIdHistory[historyIndex++] = id;

    if (historyIndex >= MESSAGE_ID_HISTORY_LENGTH) {
        historyIndex = 0;
    }
    return false;
}

private static void processTextMessage(final byte[] data) {
    synchronized (Application.getEventLock()) {

        UiEngine ui = Ui.getUiEngine();

        GlobalDialog screen = new GlobalDialog("New Notification",
                "Article ID : " + new String(data), new String(data));

        ui.pushGlobalScreen(screen, 1, UiEngine.GLOBAL_QUEUE);
    }
}

static class GlobalDialog extends PopupScreen implements
        FieldChangeListener {
    ButtonField mOKButton = new ButtonField("OK", ButtonField.CONSUME_CLICK
            | FIELD_HCENTER);
    String data = "";

    public GlobalDialog(String title, String text, String data) {
        super(new VerticalFieldManager());
        this.data = data;

        add(new LabelField(title));
        add(new SeparatorField(SeparatorField.LINE_HORIZONTAL));
        add(new LabelField(text, DrawStyle.HCENTER));

        mOKButton.setChangeListener(this);
        add(mOKButton);
    }

    public void fieldChanged(Field field, int context) {
        if (mOKButton == field) {
            try {
                ApplicationManager.getApplicationManager().launch(
                        "OrientalDailyBB");
                ApplicationManager.getApplicationManager().postGlobalEvent(
                        ID, 0, 0, data, null);

                ApplicationIndicatorRegistry reg = ApplicationIndicatorRegistry
                        .getInstance();
                reg.unregister();

                close();
            } catch (ApplicationManagerException e) {
            }
        }
    }
}
}

In this project, I checked Auto-run on startup so that this background app listener will run all the time and set the start tier to 7 in the BB App Descriptor.

However, it cannot display the popup Dialog, but I can see the device has received the push notification.

After the dialog popup and user click OK will start the OrientalDailyBB project and display the particular MainScreen.

FYI: The listener priority is higher than the OrientalDailyBB project because it is a background application. So when I install OrientalDailyBB, it will install this listener too. It happened because this listener is not in the OrientalDailyBB project folder, but is in a different folder. I did separate them to avoid the background application being terminated when the user quits from OrientalDailyBB.

1

There are 1 answers

0
Clot On BEST ANSWER

I believe that this is a threading problem. pushGlobalScreen is a message you could try to use with invokeLater.

UiApplication.getUiApplication().invokeLater(new Runnable() {
  public void run() {
    ui.pushGlobalScreen(screen, 1, UiEngine.GLOBAL_QUEUE);
  }
});

you could try to push the application to the foreground too.