Package com.rim.samples.device.phone.phoneapidemo

Source Code of com.rim.samples.device.phone.phoneapidemo.PhoneApiDemo$PhoneApiDemoMainScreen

/*
* PhoneApiDemo.java
*
* A simple program that demonstrates the Phone API.  Persistently stores the
* "talk time" for each phone number contacted while the application is running.
*
* Copyright � 1998-2011 Research In Motion Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Note: For the sake of simplicity, this sample application may not leverage
* resource bundles and resource strings.  However, it is STRONGLY recommended
* that application developers make use of the localization features available
* within the BlackBerry development platform to ensure a seamless application
* experience across a variety of languages and geographies.  For more information
* on localizing your application, please refer to the BlackBerry Java Development
* Environment Development Guide associated with this release.
*/

package com.rim.samples.device.phone.phoneapidemo;

import java.util.Date;
import java.util.Hashtable;
import java.util.Vector;

import net.rim.blackberry.api.phone.AbstractPhoneListener;
import net.rim.blackberry.api.phone.Phone;
import net.rim.blackberry.api.phone.PhoneCall;
import net.rim.device.api.command.Command;
import net.rim.device.api.command.CommandHandler;
import net.rim.device.api.command.ReadOnlyCommandMetadata;
import net.rim.device.api.system.Characters;
import net.rim.device.api.system.ControlledAccessException;
import net.rim.device.api.system.Display;
import net.rim.device.api.system.KeyListener;
import net.rim.device.api.system.PersistentObject;
import net.rim.device.api.system.PersistentStore;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.Screen;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.XYRect;
import net.rim.device.api.ui.component.BasicEditField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.component.table.DataTemplate;
import net.rim.device.api.ui.component.table.TableController;
import net.rim.device.api.ui.component.table.TableModelAdapter;
import net.rim.device.api.ui.component.table.TableModelChangeEvent;
import net.rim.device.api.ui.component.table.TableView;
import net.rim.device.api.ui.component.table.TemplateColumnProperties;
import net.rim.device.api.ui.component.table.TemplateRowProperties;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.decor.BackgroundFactory;
import net.rim.device.api.util.Persistable;
import net.rim.device.api.util.StringProvider;

/**
* The main class for the Phone API demo app.
*/
public final class PhoneApiDemo extends UiApplication {
    // Members
    // -------------------------------------------------------------------------------------
    private final PhoneApiDemoMainScreen _mainScreen;

    // Statics
    // -------------------------------------------------------------------------------------
    private static PersistentObject _persist;
    private static Vector _phoneNumberList;
    private static PhoneNumberTableModelAdapter _model;

    // Make sure a database exists for this application
    static {
        _persist = PersistentStore.getPersistentObject(0x15835f89fc421f8cL); // com.rim.samples.device.phone.phoneapidemo

        synchronized (_persist) {
            _phoneNumberList = (Vector) _persist.getContents();

            _model = new PhoneNumberTableModelAdapter();

            if (_phoneNumberList == null) {
                _phoneNumberList = new Vector();
                _persist.setContents(_phoneNumberList);
                _persist.commit();
            }
        }
    }

    /**
     * PhoneApiDemo Constructor. Creates the main screen for the app and pushes
     * it onto the display stack.
     */
    public PhoneApiDemo() {
        _mainScreen = new PhoneApiDemoMainScreen();
        /* parent. */pushScreen(_mainScreen);
    }

    /**
     * Commits the phone number records to the persistent store
     */
    private static void savePhoneNumberRecords() {
        synchronized (_persist) {
            _persist.commit();
        }
    }

    /**
     * Entry point for the application. On autostartup, it adds a new phone
     * listener for timing phone calls. On ribbon startup, a gui is presented
     * that allows users to view phone number "talk time" records.
     *
     * @param args
     *            Command-line arguments (used for differentiating between
     *            autostartup and ribbon startup).
     */
    public static void main(final String[] args) {
        if (args.length == 1 && args[0].equals("autostartup")) {
            // Create and register the object that will listen for Phone events.
            // Check for
            // ControlledAccessException as per page 69 of the BlackBerry
            // Application
            // Developer Guide, Volume 2 (Version 4.0).
            try {
                Phone.addPhoneListener(new ConcretePhoneListener());
            } catch (final ControlledAccessException e) {
                UiApplication.getUiApplication().invokeLater(new Runnable() {
                    public void run() {
                        Dialog.alert("Access to Phone API restricted by system administrator: "
                                + e.toString());
                    }
                });

                System.exit(1);
            }
        } else {
            // Create a new instance of the application and make the currently
            // running thread the application's event dispatch thread.
            new PhoneApiDemo().enterEventDispatcher();
        }
    }

    // Private inner classes
    // -----------------------------------------------------------------------

    /**
     * Adapter class for displaying phone number information in table format
     */
    private static class PhoneNumberTableModelAdapter extends TableModelAdapter {
        /**
         * @see net.rim.device.api.ui.component.table.TableModelAdapter#getNumberOfRows()
         */
        public int getNumberOfRows() {
            return _phoneNumberList.size();
        }

        /**
         * @see net.rim.device.api.ui.component.table.TableModelAdapter#getNumberOfColumns()
         */
        public int getNumberOfColumns() {
            return 1;
        }

        /**
         * @see net.rim.device.api.ui.component.table.TableModelAdapter#doGetRow(int
         *      )
         */
        protected Object doGetRow(final int index) {
            return _phoneNumberList.elementAt(index);
        }

        /**
         * @see net.rim.device.api.ui.component.table.TableModelAdapter#doRemoveRowAt(int
         *      )
         */
        protected boolean doRemoveRowAt(final int index) {
            return _phoneNumberList.removeElement(doGetRow(index));
        }

        /**
         * @see net.rim.device.api.ui.component.table.TableModelAdapter#doAddRow(Object
         *      )
         */
        protected boolean doAddRow(final Object object) {
            _phoneNumberList.addElement(object);
            return true;
        }

        /**
         * Force the table to refresh the listed elements
         */
        public void refresh() {
            notifyListeners(new TableModelChangeEvent(
                    TableModelChangeEvent.COLUMN_UPDATED, this, -1, 0));
        }
    };

    /**
     * The main screen for the Phone API application. It displays a list of
     * phone numbers that have been contacted, and allows the user to view the
     * record for each one.
     */
    private final class PhoneApiDemoMainScreen extends MainScreen {
        // Members --------------------------------------------------
        private MenuItem _deleteAllItem;
        private TableView _view;

        /**
         * PhoneApiDemoMainScreen constructor. Creates the fields and menu items
         * used on this screen.
         */
        private PhoneApiDemoMainScreen() {
            super(Manager.NO_VERTICAL_SCROLL);

            setTitle("Phone API Demo");

            _view = new TableView(_model);

            final TableController controller =
                    new TableController(_model, _view);
            _view.setController(controller);

            _view.setDataTemplateFocus(BackgroundFactory
                    .createLinearGradientBackground(Color.LIGHTBLUE,
                            Color.LIGHTBLUE, Color.BLUE, Color.BLUE));
            final DataTemplate dataTemplate = new DataTemplate(_view, 1, 1) {
                public Field[] getDataFields(final int modelRowIndex) {
                    final PhoneNumberRecord record =
                            (PhoneNumberRecord) _model.getRow(modelRowIndex);
                    final String text =
                            (String) record
                                    .getField(PhoneNumberRecord.PHONE_NUMBER);

                    final Field[] fields =
                            { new LabelField(text, Field.NON_FOCUSABLE) };

                    return fields;
                }
            };
            dataTemplate.createRegion(new XYRect(0, 0, 1, 1));
            dataTemplate.setColumnProperties(0, new TemplateColumnProperties(
                    Display.getWidth()));
            dataTemplate.setRowProperties(0, new TemplateRowProperties(32));
            _view.setDataTemplate(dataTemplate);
            dataTemplate.useFixedHeight(true);

            add(_view);

            // Menu item that deletes all the phone number records.
            _deleteAllItem =
                    new MenuItem(new StringProvider("Delete All"), 0x230010, 0);
            _deleteAllItem.setCommand(new Command(new CommandHandler() {
                /**
                 * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata,
                 *      Object)
                 */
                public void execute(final ReadOnlyCommandMetadata metadata,
                        final Object context) {
                    if (Dialog.ask(Dialog.D_DELETE) == Dialog.DELETE) {
                        while (_model.getNumberOfRows() > 1) {
                            _model.removeRowAt(0, true);
                        }
                        if (_model.getNumberOfRows() == 1) {
                            _model.removeRowAt(0);
                        }
                        PhoneApiDemo.savePhoneNumberRecords();
                    }
                }
            }));

            addKeyListener(new PhoneApiDemoKeyListener(this));
        }

        /**
         * @see net.rim.device.api.ui.container.MainScreen#onExposed()
         */
        protected void onExposed() {
            _model.refresh();
        }

        /**
         * Creates the menu for this screen
         *
         * @see net.rim.device.api.ui.container.MainScreen#makeMenu(Menu,int)
         */
        protected void makeMenu(final Menu menu, final int instance) {
            super.makeMenu(menu, instance);

            // If there are any items in the list, add menu items to view and
            // delete them.
            if (_model.getNumberOfRows() > 0) {
                final int index = _view.getRowNumberWithFocus();
                final PhoneNumberRecord record =
                        (PhoneNumberRecord) _model.getRow(index);
                menu.add(new View(record));
                menu.addSeparator();
                menu.add(new Delete(record));
                menu.add(_deleteAllItem);
                menu.addSeparator();
            }
        }

        // Private inner classes representing menu items and listeners used by
        // this screen ---------

        /**
         * This class is a menu item allowing a user to view a phone number
         * record.
         */
        private final class View extends MenuItem {
            // Members ----------------------------------------------
            private final PhoneNumberRecord _record;

            /**
             * Constructs a menu item to view a record when invoked
             *
             * @param record
             *            The record to view
             */
            private View(final PhoneNumberRecord record) {
                super(new StringProvider("View"), 0x230020, 100);
                _record = record;
                this.setCommand(new Command(new CommandHandler() {
                    /**
                     * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata,
                     *      Object)
                     */
                    public void execute(final ReadOnlyCommandMetadata metadata,
                            final Object context) {
                        final MainScreen screen = new MainScreen();

                        screen.setTitle(new LabelField("View Phone Record"));

                        final PhoneNumberRecordDisplayer displayer =
                                new PhoneNumberRecordDisplayer(_record);
                        final Vector fields = displayer.getFields();
                        final int numFields = fields.size();

                        for (int i = 0; i < numFields; ++i) {
                            screen.add((Field) fields.elementAt(i));
                        }

                        screen.addKeyListener(new PhoneApiDemoKeyListener(
                                screen));

                        PhoneApiDemo.this.pushScreen(screen);
                    }
                }));
            }
        }

        /**
         * This class is a menu item allowing a user to delete a phone number
         * record
         */
        private final class Delete extends MenuItem {

            /**
             * Constructs a menu item to delete a phone record when invoked
             *
             * @param record
             *            The phone record to delete
             */
            private Delete(final PhoneNumberRecord record) {
                super(new StringProvider("Delete"), 0x230030, 110);
                this.setCommand(new Command(new CommandHandler() {
                    /**
                     * Deletes the phone record
                     *
                     * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata,
                     *      Object)
                     */
                    public void execute(final ReadOnlyCommandMetadata metadata,
                            final Object context) {
                        if (Dialog.ask(Dialog.D_DELETE) == Dialog.DELETE) {
                            _model.removeRowAt(_view.getRowNumberWithFocus());
                            PhoneApiDemo.savePhoneNumberRecords();
                        }
                    }
                }));
            }
        }
    }

    /**
     * Persistable phone number record
     */
    private static final class PhoneNumberRecord implements Persistable {
        // Members
        // ---------------------------------------------------------------------------------
        private final Vector _fields;
        private long _startTime;

        // Constants
        // -------------------------------------------------------------------------------
        private static final int PHONE_NUMBER = 0;
        private static final int TALK_TIME = 1;

        /**
         * Constructs a PhoneNumberRecord from a phone number
         *
         * @param phoneNumber
         *            The phone number of the record to be created
         */
        private PhoneNumberRecord(final String phoneNumber) {
            _fields = new Vector();
            _fields.addElement(phoneNumber);
            _fields.addElement(new Long(0));
            _startTime = 0;
        }

        /**
         * Retrieves one of this record's fields
         *
         * @param index
         *            The index of the field to retrieve
         * @return The field
         */
        private Object getField(final int index) {
            return _fields.elementAt(index);
        }

        /**
         * Sets one of this record's fields
         *
         * @param index
         *            The index of the field to set
         * @param o
         *            The object that the field is set to
         */
        private void setField(final int index, final Object o) {
            _fields.setElementAt(o, index);
        }

        /**
         * Determines if this record and the parameter refer to the same phone
         * number record.
         *
         * @param o
         *            The object to check for equality
         * @return True if this record and o refer to the same phone number
         *         record; false otherwise
         */
        public boolean equals(final Object o) {
            if (o instanceof PhoneNumberRecord) {
                final PhoneNumberRecord record = (PhoneNumberRecord) o;
                final String phoneNumber1 =
                        (String) record._fields.elementAt(PHONE_NUMBER);
                final String phoneNumber2 =
                        (String) _fields.elementAt(PHONE_NUMBER);

                return phoneNumber1.equals(phoneNumber2);
            }

            return false;
        }

        /**
         * @see java.lang.Object#hashCode()
         */
        public int hashCode() {
            final Object phoneNumber = _fields.elementAt(PHONE_NUMBER);
            return phoneNumber == null ? 0 : phoneNumber.hashCode();
        }

        /**
         * Determines whether this record is currently recording "talk time"
         *
         * @return True if this record is currently recording "talk time"; false
         *         otherwise
         */
        private boolean isActive() {
            return _startTime != 0;
        }

        /**
         * Causes this record to start recording "talk time"
         */
        public void start() {
            _startTime = new Date().getTime();
        }

        /**
         * Causes this record to temporarily stop recording "talk time"
         */
        private void putOnHold() {
            long talkTime = ((Long) _fields.elementAt(TALK_TIME)).longValue();
            talkTime += new Date().getTime() - _startTime;
            _fields.setElementAt(new Long(talkTime), TALK_TIME);
            _startTime = 0;
        }

        /**
         * Causes this record to resume recording "talk time"
         */
        private void resume() {
            start();
        }

        /**
         * Causes this record to stop recording "talk time"
         */
        private void end() {
            putOnHold();
        }
    }

    /**
     * This class is used to display the information inside a phone number
     * record on the screen using fields.
     */
    private static final class PhoneNumberRecordDisplayer {
        // Members ----------------------------------------------
        private final BasicEditField _phoneNumber;
        private final BasicEditField _talkTime;

        /**
         * Constructs a collection of fields to display the phone number
         * record's information.
         *
         * @param phoneNumberRecord
         *            The phone number record to display
         */
        private PhoneNumberRecordDisplayer(
                final PhoneNumberRecord phoneNumberRecord) {
            final String phoneNumber =
                    (String) phoneNumberRecord
                            .getField(PhoneNumberRecord.PHONE_NUMBER);
            long talkTime =
                    ((Long) phoneNumberRecord
                            .getField(PhoneNumberRecord.TALK_TIME)).longValue();

            _phoneNumber = new BasicEditField("Phone Number: ", phoneNumber);
            _phoneNumber.setEditable(false);

            // Convert milliseconds into hh:mm:ss format.
            final int hours = (int) (talkTime / (1000 * 60 * 60));
            talkTime %= 1000 * 60 * 60;
            final int minutes = (int) (talkTime / (1000 * 60));
            talkTime %= 1000 * 60;
            final int seconds = (int) (talkTime / 1000);
            final StringBuffer timeString = new StringBuffer();

            if (hours > 0) {
                if (hours < 10) {
                    timeString.append(0);
                }

                timeString.append(hours).append(':');
            }

            if (minutes < 10) {
                timeString.append(0);
            }

            timeString.append(minutes).append(':');

            if (seconds < 10) {
                timeString.append(0);
            }

            timeString.append(seconds);
            _talkTime =
                    new BasicEditField("Talk Time: ", timeString.toString());
            _talkTime.setEditable(false);
        }

        /**
         * Retrives a vector containing this displayer's fields.
         *
         * @return This displayer's fields.
         */
        private Vector getFields() {
            final Vector fields = new Vector();
            fields.addElement(_phoneNumber);
            fields.addElement(_talkTime);

            return fields;
        }
    }

    /**
     * Phone listener object. Listens for the callConnected, callDisconnected,
     * callHeld, and callResumed events and calculates talk time for each unique
     * phone number.
     */
    private static final class ConcretePhoneListener extends
            AbstractPhoneListener {
        // Members ----------------------------------------------

        // Helper object for searching the list of records
        private final PhoneNumberRecord _searchRecord = new PhoneNumberRecord(
                "");

        // Maps call IDs to their phone numbers
        private final Hashtable _phoneNumberTable = new Hashtable();

        /**
         * Default constructor
         */
        ConcretePhoneListener() {
            // Not implemented
        }

        /**
         * Called when a phone call is connected. Finds the record with the
         * call's phone number (or creates a new one if one doesn't exist),
         * starts the "talk time" timer, and saves the record list.
         *
         * @param callId
         *            The ID of the call that connected
         */
        public void callConnected(final int callId) {
            final PhoneCall phoneCall = Phone.getCall(callId);
            final String phoneNumber = phoneCall.getDisplayPhoneNumber();
            _phoneNumberTable.put(new Integer(callId), phoneNumber);
            PhoneNumberRecord record =
                    getPhoneNumberRecordByPhoneNumber(phoneNumber);

            if (record == null) {
                // No record exists yet with this phone number, so create one
                // and put it in the list.
                record = new PhoneNumberRecord(phoneNumber);
                _model.addRow(record);
            }

            if (!record.isActive()) {
                record.start();
                PhoneApiDemo.savePhoneNumberRecords();
            }
        }

        /**
         * Called when a phone call is disconnected. Finds the record with the
         * call's phone number, stops the "talk time" timer, and saves the
         * phoneNumberRecord list.
         *
         * @param callId
         *            The ID of the call that disconnected
         */
        public void callDisconnected(final int callId) {
            final PhoneNumberRecord record = getPhoneNumberRecord(callId);

            // If an incoming phone call is ignored by the user rather than
            // answered, then
            // no record exists in _phoneNumberTable that matches callId. Thus,
            // record may
            // be null. If that's the case, do nothing; otherwise, proceed as
            // normal and
            // end the call.
            if (record != null) {
                _phoneNumberTable.remove(new Integer(callId));

                if (record.isActive()) {
                    record.end();
                    PhoneApiDemo.savePhoneNumberRecords();
                }
            }
        }

        /**
         * Called when a phone call is put on hold. Finds the record with the
         * call's phone number, stops the "talk time" timer, and saves the
         * record list.
         *
         * @param callId
         *            The ID of the call that was put on hold.
         */
        public void callHeld(final int callId) {
            final PhoneNumberRecord record = getPhoneNumberRecord(callId);

            if (record.isActive()) {
                record.putOnHold();
                PhoneApiDemo.savePhoneNumberRecords();
            }
        }

        /**
         * Called when a phone call is resumed (taken off hold). Finds the
         * record with the call's phone number, starts the "talk time" timer,
         * and saves the record list.
         *
         * @param callId
         *            The ID of the call that was resumed
         */
        public void callResumed(final int callId) {
            final PhoneNumberRecord record = getPhoneNumberRecord(callId);

            if (!record.isActive()) {
                record.resume();
                PhoneApiDemo.savePhoneNumberRecords();
            }
        }

        /**
         * Retrieves a phone number record by call ID. Returns null if no such
         * record exists
         *
         * @param callId
         *            The ID of the phone number record to retrieve
         * @return The phone number record, or null if no record matches callId
         */
        private PhoneNumberRecord getPhoneNumberRecord(final int callId) {
            final String phoneNumber =
                    (String) _phoneNumberTable.get(new Integer(callId));
            return getPhoneNumberRecordByPhoneNumber(phoneNumber);
        }

        /**
         * Retrieves a phone number record by phone number. Returns null if no
         * such record exists.
         *
         * @param phoneNumber
         *            The phone number of the phone number record to retrieve
         * @return The phone number record, or null if no record matches
         *         phoneNumber
         */
        private PhoneNumberRecord getPhoneNumberRecordByPhoneNumber(
                final String phoneNumber) {
            _searchRecord.setField(PhoneNumberRecord.PHONE_NUMBER, phoneNumber);
            final int index = _phoneNumberList.indexOf(_searchRecord);

            if (index != -1) {
                return (PhoneNumberRecord) _model.getRow(index);
            }

            return null;
        }
    }

    /**
     * This class implements a key listener for a screen so a menu is displayed
     * when the user presses ENTER.
     */
    private static final class PhoneApiDemoKeyListener implements KeyListener {
        private final Screen _screen;

        /**
         * Creates a new PhoneApiDemoKeyListener object
         *
         * @param screen
         *            The screen with to display the menu on
         */
        public PhoneApiDemoKeyListener(final Screen screen) {
            _screen = screen;
        }

        // KeyListener methods
        // ---------------------------------------------------------------------
        /**
         * @see net.rim.device.api.system.KeyListener#keyChar(char,int,int)
         */
        public boolean
                keyChar(final char key, final int status, final int time) {
            if (key == Characters.ENTER) {
                return _screen.onMenu(0);
            }

            return false;
        }

        /**
         * @see net.rim.device.api.system.KeyListener#keyDown(int,int)
         */
        public boolean keyDown(final int keycode, final int time) {
            return false;
        }

        /**
         * @see net.rim.device.api.system.KeyListener#keyUp(int,int)
         */
        public boolean keyUp(final int keycode, final int time) {
            return false;
        }

        /**
         * @see net.rim.device.api.system.KeyListener#keyRepeat(int,int)
         */
        public boolean keyRepeat(final int keycode, final int time) {
            return false;
        }

        /**
         * @see net.rim.device.api.system.KeyListener#keyStatus(int,int)
         */
        public boolean keyStatus(final int keycode, final int time) {
            return false;
        }
    }
}
TOP

Related Classes of com.rim.samples.device.phone.phoneapidemo.PhoneApiDemo$PhoneApiDemoMainScreen

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.