×

Discussion Board

Results 1 to 8 of 8
  1. #1
    Registered User
    Join Date
    Nov 2013
    Posts
    5

    Question read contacts (PIM)

    Hi ALL

    I have a problem with my tiny J2ME application.
    The application opens contacts list (PIM API), calculates a number of contacs and displays the number as Alert.
    The application works as expected when it is unsigned.
    But digitally signed application (by valid certificate) does not work.
    The signed application threw following exception:
    java.lang.RuntimeException: Blocking call performed in the event thread
    at javax.microedition.lcdui.DisplayEventHandlerImpl.preemptDisplay(), bci=50
    at com.sun.midp.security.PermissionDialog.<init>(), bci=286
    at com.sun.midp.security.SecurityHandler.askUserForOneShotPermission(), bci=33
    at com.sun.midp.security.SecurityHandler.checkForPermission(), bci=736
    at com.sun.midp.security.SecurityHandler.checkForPermission(), bci=26
    at com.sun.midp.midletsuite.MIDletSuiteImpl.checkForPermission(), bci=20
    at com.sun.midp.midletsuite.MIDletSuiteImpl.checkForPermission(), bci=18
    at com.sun.midp.main.CldcAccessControlContext.checkPermissionImpl(), bci=34
    at com.sun.j2me.security.AccessControlContextAdapter.checkPermission(), bci=4
    at com.sun.j2me.security.AccessController.checkPermission(), bci=29
    at com.sun.j2me.app.AppPackage.checkForPermission(), bci=31
    at com.sun.j2me.pim.PIMImpl.checkPermissions(), bci=99
    at com.sun.j2me.pim.PIMImpl.openPIMList(), bci=19
    - fidomoneylending.moneyadvance.conrectsreader.MainForm$ContactCounterTask.run(Main.java:144)
    - fidomoneylending.moneyadvance.conrectsreader.MainForm.commandAction(Main.java:80)
    at javax.microedition.lcdui.Display$ChameleonTunnel.callScreenListener(), bci=39
    at com.sun.midp.chameleon.layers.SoftButtonLayer.processCommand(), bci=62
    at com.sun.midp.chameleon.layers.SoftButtonLayer.soft2(), bci=119
    at com.sun.midp.chameleon.layers.SoftButtonLayer.keyInput(), bci=102
    at com.sun.midp.chameleon.CWindow.keyInput(), bci=30
    at javax.microedition.lcdui.Display$DisplayEventConsumerImpl.handleKeyEvent(), bci=43
    at com.sun.midp.lcdui.DisplayEventListener.process(), bci=252
    at com.sun.midp.events.EventQueue.run(), bci=130
    at java.lang.Thread.run(Thread.java:743)
    It was a bit weird because unsigned version of the application worked (but asked several questions to grant permissions to read user data "Contacts").
    I improved the application by adding possibility to run functionality which calculated number of contacts in a separate thread.
    The improved version of the application works for unsigned application (in both modes: single-threaded and multithreaded).
    The signed application throws RuntimeError("Blocking call performed in the event thread") in single-threaded mode and hangs in multi-threaded mode

    There is one interesting observation for the singned application in multi-threaded mode.
    If at the very first run of the application give answers "Always" on asked questions then close application (when it hangs) and run it again then application calculates number of contacts as expected.

    I would like to run my application when it is digitally signed.
    Can anybody help me to fix the issue?

    Regards,
    Dmitry

    P.S. I tested my application on emulator (Oracle Java(TM) Platform Micro Edition SDK 3.4) and mobile phone "Asha 200".

    Below is a code of the application:

    Code:
    package fidomoneylending.moneyadvance.conrectsreader;
    
    import java.util.Enumeration;
    import javax.microedition.lcdui.Alert;
    import javax.microedition.lcdui.AlertType;
    import javax.microedition.lcdui.ChoiceGroup;
    import javax.microedition.lcdui.Command;
    import javax.microedition.lcdui.CommandListener;
    import javax.microedition.lcdui.Display;
    import javax.microedition.lcdui.Displayable;
    import javax.microedition.lcdui.Form;
    import javax.microedition.lcdui.StringItem;
    import javax.microedition.midlet.*;
    import javax.microedition.pim.ContactList;
    import javax.microedition.pim.PIM;
    
    /**
     * @author Dmitry Trunikov <dmitry.trunikov@zoral.com.ua>
     */
    public class Main extends MIDlet {
    
        public Main() {
            MainForm mf = new MainForm(this);
            Display d = Display.getDisplay(this);
            d.setCurrent(mf);
        }
    
        public void startApp() {
        }
    
        public void pauseApp() {
        }
    
        public void destroyApp(boolean unconditional) {
            notifyDestroyed();
        }
    
        public void exitApp() {
            destroyApp(false);
        }
    
    }
    
    class MainForm extends Form implements CommandListener {
    
        private final Main midlet;
        private final Command cmdExit;
        private final Command cmdReadContacts;
        private final ChoiceGroup chgMode;
        private final StringItem itemError;
    
        public MainForm(Main midlet) {
            super("Reader of contact");
            append("Simple J2ME application to read and display number of contacts.");
            this.chgMode = new ChoiceGroup("Run mode", ChoiceGroup.POPUP, new String[]{"Single-threaded", "Multi-threaded"}, null);
            append(this.chgMode);
            this.itemError = new StringItem("", "");
            append(this.itemError);
            this.midlet = midlet;
            this.cmdExit = new Command("Quit", "Exit", Command.EXIT, 0);
            this.cmdReadContacts = new Command("Read", "Read Contacts", Command.SCREEN, 2);
            addCommand(cmdExit);
            addCommand(cmdReadContacts);
            setCommandListener(this);
        }
    
        public void commandAction(Command c, Displayable d) {
            if (c == cmdExit) {
                midlet.exitApp();
            } else if (c == cmdReadContacts) {
                clearError();
                Display display = Display.getDisplay(midlet);
                try {
                    String title = "Contacts [";
                    ContactCounterTask task = new ContactCounterTask();
                    int choice = this.chgMode.getSelectedIndex();
                    switch (choice) {
                        case 0: // single-threaded mode
                            title += "single-threaded";
                            task.run();
                            break;
                        case 1: // multi-threaded mode
                            title += "multi-threaded";
                            Thread thrd = new Thread(task);
                            thrd.start();
                            thrd.join();
                            break;
                        default:
                            return;
                    }
                    title += "]";
                    int n = task.getN();
                    Alert alrtContacts = new Alert(title, "Number of contacts: " + n, null, AlertType.INFO);
                    display.setCurrent(alrtContacts, this);
                } catch (Throwable e) {
                    displayError(e);
                }
            }
        }
            
        private void clearError() {
            itemError.setLabel("");
            itemError.setText("");
        }
        
        private void displayError(Throwable e) {
            String msg = e.getMessage();
            System.err.println("APP ERROR: " + msg);
            e.printStackTrace();
            itemError.setLabel("ERROR: ");
            itemError.setText(msg);
            Alert alrtEx = new Alert("Error", msg, null, AlertType.ERROR);
            alrtEx.setTimeout(Alert.FOREVER);
            Display display = Display.getDisplay(midlet);
            display.setCurrent(alrtEx, this);
        }
    
        class ContactCounterTask implements Runnable {
    
            private int n = -1;
    
            protected volatile boolean stop = false;
    
            void cancel() {
                stop = true;
            }
    
            ContactCounterTask() {
            }
    
            public int getN() {
                return n;
            }
    
            public void run() {
                if (stop) {
                    return;
                }
                PIM pim = PIM.getInstance();
                try {
                    if (stop) {
                        return;
                    }
                    ContactList listContacts = (ContactList) pim.openPIMList(PIM.CONTACT_LIST, PIM.READ_ONLY);
                    try {
                        if (stop) {
                            return;
                        }
                        Enumeration itemsContacts = listContacts.items();
                        if (itemsContacts != null) {
                            if (stop) {
                                return;
                            }
                            while (itemsContacts.hasMoreElements()) {
                                if (stop) {
                                    return;
                                }
                                itemsContacts.nextElement();
                                n++;
                            }
                        }
                    } finally {
                        listContacts.close();
                    }
                } catch (Throwable e) {
                    displayError(e);
                }
            }
    
        }
    }

  2. #2
    Nokia Developer Champion
    Join Date
    Mar 2013
    Posts
    686

    Re: read contacts (PIM)

    This is a known issue, the solution to this issue is not call secure API (i.e. API that require permission for) from the System/CommandCallback/UI thread.
    I suggest you move your secure API call (in this case the PIM calls) to a new Thread (Make sure you don't have any deadlocks to prevent you from the "Hang" situation your referring.
    Heard of DVLUP? Join here

  3. #3
    Registered User
    Join Date
    Nov 2013
    Posts
    5

    Re: read contacts (PIM)

    Hi shai.i,

    As I stated the application can run in two modes single-threaded and multi-threaded. In the multi-threaded mode calls to PIM API are executed in a separate thread as you propose. Digitally signed application hangs (the thread never finishes)
    It would be nice if you review my code (see my very first message) or give me any example (or link on example) how to read contacts correctly.

    I will be grateful for any help you can provide.

    Dmitry

  4. #4
    Nokia Developer Champion
    Join Date
    Mar 2013
    Posts
    686

    Re: read contacts (PIM)

    There is no such thing that a thread never finish, you must have a deadlock somewhere.
    I would suggest you to remove this line "thrd.join();" since you are in fact blocking the system main thread (that called the command action) and it is the same as calling the PIM api from that same thread...
    Heard of DVLUP? Join here

  5. #5
    Registered User
    Join Date
    Nov 2013
    Posts
    5

    Re: read contacts (PIM)

    Quote Originally Posted by shai.i View Post
    I would suggest you to remove this line "thrd.join();" since you are in fact blocking the system main thread (that called the command action) and it is the same as calling the PIM api from that same thread...
    Hi Shai,

    Thank you for your suggestion, but it didn't help a lot.
    I've removed the '*.join()' in main thread and added a new command to allow read result of the task.
    The application doesn't hangs now but member "number of contacts" is not initialized by the task (I tried to read result in a minutes after starting of the task)

    I can't beleive that such trivial task as reading of contacts (in digitally signed application) has no solution but it seems so.
    Can anybody to help me? Sample code will be very appreciated.

    BTW can anybody tell me how can I escalate this issue request to Nokia's developers/support?
    I spent some time for my project and can't release it because of this issue. It is desperately boring situation as I can't explain my customers why the application works unsigned version and hangs digitally signed one.

    Regards,
    Dmitry

    Regards,
    Dmitry

    P.S. Current code of the sample application:

    Code:
    package fidomoneylending.moneyadvance.conrectsreader;
    
    import java.util.Enumeration;
    import javax.microedition.lcdui.Alert;
    import javax.microedition.lcdui.AlertType;
    import javax.microedition.lcdui.ChoiceGroup;
    import javax.microedition.lcdui.Command;
    import javax.microedition.lcdui.CommandListener;
    import javax.microedition.lcdui.Display;
    import javax.microedition.lcdui.Displayable;
    import javax.microedition.lcdui.Form;
    import javax.microedition.lcdui.StringItem;
    import javax.microedition.midlet.*;
    import javax.microedition.pim.ContactList;
    import javax.microedition.pim.PIM;
    
    /**
     * @author Dmitry Trunikov <dmitry.trunikov@zoral.com.ua>
     */
    public class Main extends MIDlet {
    
        public Main() {
            MainForm mf = new MainForm(this);
            Display d = Display.getDisplay(this);
            d.setCurrent(mf);
        }
    
        public void startApp() {
        }
    
        public void pauseApp() {
        }
    
        public void destroyApp(boolean unconditional) {
            notifyDestroyed();
        }
    
        public void exitApp() {
            destroyApp(false);
        }
    
    }
    
    class MainForm extends Form implements CommandListener {
    
        private final Main midlet;
        private final Command cmdExit;
        private final Command cmdReadContacts;
        private final Command cmdDisplayResult;
        private final ChoiceGroup chgMode;
        private final StringItem itemError;
        private final ContactCounterTask task;
    
        public MainForm(Main midlet) {
            super("Reader of contact");
            append("Simple J2ME application to read and display number of contacts.");
            this.chgMode = new ChoiceGroup("Run mode", ChoiceGroup.POPUP, new String[]{"Single-threaded", "Multi-threaded"}, null);
            append(this.chgMode);
            this.itemError = new StringItem("", "");
            append(this.itemError);
            this.midlet = midlet;
            this.cmdExit = new Command("Quit", "Exit", Command.EXIT, 0);
            this.cmdReadContacts = new Command("Read", "Read Contacts", Command.SCREEN, 2);
            this.cmdDisplayResult = new Command("Result", "Display Result", Command.SCREEN, 3);
            addCommand(cmdExit);
            addCommand(cmdReadContacts);
            addCommand(cmdDisplayResult);
            this.task = new ContactCounterTask();
            setCommandListener(this);
        }
    
        public void commandAction(Command c, Displayable d) {
            if (c == cmdExit) {
                midlet.exitApp();
            } else if (c == cmdDisplayResult) {
                if (task.hasError()) {
                    Throwable e = task.getError();
                    displayError(e);
                } else {
                    Display display = Display.getDisplay(midlet);
                    int n = task.getN();
                    Alert alrtContacts = new Alert("Result", "Number of contacts: " + n, null, AlertType.INFO);
                    display.setCurrent(alrtContacts, this);
                }
            } else if (c == cmdReadContacts) {
                clearError();
                Display display = Display.getDisplay(midlet);
                try {
                    int choice = this.chgMode.getSelectedIndex();
                    switch (choice) {
                        case 0: // single-threaded mode
                            task.run();
                            break;
                        case 1: // multi-threaded mode
                            Thread thrd = new Thread(task);
                            thrd.start();
                            //thrd.join();
                            break;
                        default:
                            return;
                    }
                } catch (Throwable e) {
                    displayError(e);
                }
            }
        }
            
        private void clearError() {
            itemError.setLabel("");
            itemError.setText("");
        }
        
        private void displayError(Throwable e) {
            String msg = e.getMessage();
            System.err.println("APP ERROR: " + msg);
            e.printStackTrace();
            itemError.setLabel("ERROR: ");
            itemError.setText(msg);
            Alert alrtEx = new Alert("Error", msg, null, AlertType.ERROR);
            alrtEx.setTimeout(Alert.FOREVER);
            Display display = Display.getDisplay(midlet);
            display.setCurrent(alrtEx, this);
        }
    
        class ContactCounterTask implements Runnable {
    
            private int n;
    
            private Throwable error;
    
            ContactCounterTask() {
                reset();
            }
            
            public void reset() {
                this.n = -1;
                this.error = null;
            }
            
            public boolean hasError() {
                return error != null;
            }
    
            public int getN() {
                return n;
            }
            
            public Throwable getError() {
                return error;
            }
    
            public void run() {
                PIM pim = PIM.getInstance();
                try {
                    ContactList listContacts = (ContactList) pim.openPIMList(PIM.CONTACT_LIST, PIM.READ_ONLY);
                    try {
                        Enumeration itemsContacts = listContacts.items();
                        if (itemsContacts != null) {
                            while (itemsContacts.hasMoreElements()) {
                                itemsContacts.nextElement();
                                n++;
                            }
                        }
                    } finally {
                        listContacts.close();
                    }
                } catch (Throwable e) {
                    this.error = e;
                }
            }
    
        }
    }

  6. #6
    Nokia Developer Champion
    Join Date
    Mar 2013
    Posts
    686

    Re: read contacts (PIM)

    trunikov: I don't understand what is the problem now that you've removed the thread.join() everything works well
    I just tested your test midlet on an Asha 501 phone with 2 contacts in it and I received the result n=1 ( notice that this is because you set n=-1 in the reset function instead of n=0 )

    In short everything works fine and it manage to read the contacts with out any issue.
    If you or your clients need further help in the development then you can contact me at contact@the-futuresoft.com we're experts in making mobile apps for all platforms and are recommended by Nokia in their consultancy network http://developer.nokia.com/resources...cy-network/P20 (Future soft)
    Heard of DVLUP? Join here

  7. #7
    Registered User
    Join Date
    Nov 2013
    Posts
    5

    Re: read contacts (PIM)

    Quote Originally Posted by shai.i View Post
    I just tested your test midlet on an Asha 501 phone with 2 contacts in it and I received the result n=1 ( notice that this is because you set n=-1 in the reset function instead of n=0 )
    Hi Shai,

    Thanks for your effort to help me and patience.

    Did you test digitally signed midlet?
    Unsigned midlet works for me too.

  8. #8
    Registered User
    Join Date
    Nov 2013
    Posts
    5

    Re: read contacts (PIM)

    Hi ALL,

    I sent report about this issue to Nokia support. And received an answer today. This is snippet from this answer:

    Our java expert tested this, and based on his tests, the signed version indeed gets stuck in the first start up with Asha 200. The second start up works.
    However, with a newer device (Asha 503), it works also with the first attempt.
    Based on that, it is possible that there is some issues in the device firmware with the permission handling. Unfortunately that device is so old that the firmware changes cannot be expected.
    Hope this info will be helpful for others.

    Thank you for all who tried to help me especially Shai

    Regards,
    Dmitry

Similar Threads

  1. How to read contacts
    By sreehari434 in forum Mobile Java General
    Replies: 8
    Last Post: 2009-11-28, 06:51
  2. Replies: 13
    Last Post: 2008-07-23, 17:06
  3. read contacts in S40
    By oscarm in forum Mobile Java General
    Replies: 6
    Last Post: 2008-02-27, 18:13
  4. How to read SIM card contacts?
    By shalmali.mehta in forum Symbian
    Replies: 3
    Last Post: 2007-10-29, 14:22
  5. EtelBgsm.h - read contacts
    By fabionokia in forum Symbian
    Replies: 1
    Last Post: 2003-12-07, 12:54

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
×