бесплатные рефераты

Использование платформы j2me для мобильных телефонов при организации видеонаблюдений

Листинг 3.2 - Выравнивание элементов по центру

/**

* Layout the given parent container children

* @param parent the given parent container

*/

public class CenterLayout extends Layout {

public void layoutContainer (Container parent) {

int components = parent.getComponentCount();

Style parentStyle = parent.getStyle();

int centerPos = parent.getLayoutWidth() / 2 +

parentStyle.getMargin (Component.LEFT);

int y = parentStyle.getMargin (Component.TOP);

for (int iter = 0; iter < components; iter++) {

Component current = parent.getComponentAt(iter);

Dimension d = current.getPreferredSize();

current.setSize(d);

current.setX (centerPos - d.getWidth() / 2);

Style currentStyle = current.getStyle();

y += currentStyle.getMargin (Component.TOP);

current.setY(y);

y += d.getHeight() + currentStyle.getMargin (Component.BOTTOM);

}

}

/**

* Returns the container preferred size

*

* @param parent the parent container

* @return the container preferred size

*/

public Dimension getPreferredSize (Container parent) {

int components = parent.getComponentCount();

Style parentStyle = parent.getStyle();

int height = parentStyle.getMargin (Component.TOP)

+ parentStyle.getMargin (Component.BOTTOM);

int marginX = parentStyle.getMargin (Component.RIGHT)

+ parentStyle.getMargin (Component.LEFT);

int width = marginX;

for (int iter = 0; iter < components; iter++) {

Component current = parent.getComponentAt(iter);

Dimension d = current.getPreferredSize();

Style currentStyle = current.getStyle();

width = Math.max (d.getWidth() + marginX

+ currentStyle.getMargin (Component.RIGHT) +

currentStyle.getMargin (Component.LEFT), width);

height += currentStyle.getMargin (Component.TOP) + d.getHeight() +

currentStyle.getMargin (Component.BOTTOM);

}

Dimension size = new Dimension (width, height);

return size;

}

}

В следующем листинге 3.3 содержится программный код экранной формы-заставки с применением разработанного класса-менеджера размещения элементов CenterLayout.

Листинг 3.3 - Экранная форма заставки

public class SplashScreen extends Form {

public SplashScreen() {

setLayout (new CenterLayout());

setTitle ("Welcome");

addComponent (new Label(("Video observer")));

addComponent (new Label(("by M. Luskanova")));

}

}

62

Рисунок 3.2 - Главное меню

Для создания главного меню (рисунок 3.2) был реализован специальный класс, который представляет собой один пункт меню. Каждый элемент такого меню является контейнером с несколькими строчками и представляет их как единое целое. Такая функциональность достигается за счет наследования от класса Container и переопределения методов getComponentAt() и pointerPressed() (листинг 3.4).

Метод getComponentAt (int x, int y) вызывается, когда необходимо вернуть компонент, находящийся в заданной точке экрана. Если этот метод не переопределить, то будет возвращен элемент, входящий в данный контейнер. Переопределение второго метода гарантирует, что не произойдет никакой обработки (например, выделения) в случае, если пользователь выберет какой-либо элемент данного пункта.

Метод pointerPressed (int x, int y) выполняется в случае нажатия сенсорного указателя. Если этот метод не переопределить, то будет выделен компонент внутри данного контейнера.

Листинг 3.4 - Пункт главного меню

public class MylistItem extends Container implements FocusListener {

private Style selectedStyle =

UIManager.getInstance().getComponentStyle ("_selected");

private Style unselectedStyle =

UIManager.getInstance().getComponentStyle ("_unselected");

/**

* This method provides performance of

* included components as one

*/

public Component getComponentAt (int x, int y) {

return this;

}

/**

* Do nothing when user clicks on any element

*/

public void pointerPressed (int x, int y) {

}

/**

* Returns "_unselected" style by default

*/

protected String getUIID() {

return "_unselected";

}

/**

* Change style for selected menu item

*/

public void focusGained (Component cmp) {

cmp.setStyle(selectedStyle);

}

/**

* Change style for unselected menu item

*/

public void focusLost (Component cmp) {

cmp.setStyle(unselectedStyle);

}

}

Метод getUIID() переопределен для того, чтобы возвращать стиль невыделенного элемента. Метод focusGained() вызывается при получении данным пунктом меню фокуса, и поэтому требуется этот пункт отрисовать другим стилем.

При перемещении фокуса на следующий пункт меню нужно поменять стиль этого пункта на обычный, что и выполняется в переопределенном методе focusLost().

Само меню создается следующим образом с использованием вышеуказанного класса (листинг 3.5). Preferences.getInstanse() - это объект, который хранит все сделанные пользователем настройки.

Листинг 3.5 - Создание главного меню

Preferences pr = Preferences.getInstanse();

setLayout (new BoxLayout (BoxLayout.Y_AXIS));

getContentPane().setIsScrollVisible(false);

MylistItem mli = new MylistItem (MainMenuConstatns.SCHEDULE, "Schedule");

if (! pr.isStartRecordFromUnbounded()) {

mli.addString ("from" +

pr.getStartRecordFromCalendar().get (java.util. Calendar.YEAR) +"." +

pr.getStartRecordFromCalendar().get (java.util. Calendar.MONTH) +"." +

pr.getStartRecordFromCalendar().get (java.util. Calendar.DAY_OF_MONTH)

+" "+pr.getStartRecordFromCalendar().get (java.util. Calendar.HOUR_OF_DAY)

+":"+pr.getStartRecordFromCalendar().get (java.util. Calendar.MINUTE));

}

if (! pr.isEndRecordAtUnbounded()) {

mli.addString ("till" +

pr.getEndsRecordAtCalendar().get (java.util. Calendar.YEAR) +"." +

pr.getEndsRecordAtCalendar().get (java.util. Calendar.MONTH) +"." +

pr.getEndsRecordAtCalendar().get (java.util. Calendar.DAY_OF_MONTH) + " " +

pr.getEndsRecordAtCalendar().get (java.util. Calendar.HOUR_OF_DAY) +":" +

pr.getEndsRecordAtCalendar().get (java.util. Calendar.MINUTE));

}

if (! pr.isStartRecordFromUnbounded() ||! pr.isEndRecordAtUnbounded()) {

if (pr.isScheduleIsActive()) {

mli.addString ("Active");

} else {

mli.addString ("Disabled");

}

}

addComponent(mli);

mli = new MylistItem (MainMenuConstatns.TRANSLATE_VIDEO, "Translate video");

addComponent(mli);

if (pr.getBTConnectionURL()!= "") {

mli.addString ("via bluetooth to "+pr.getBTFriendlyName());

}

if (pr.getSaveVideoToFile()!= "") {

mli.addString (pr.getSaveVideoToFile());

}

if (pr.getMovNotification()!= "") {

String msgType = (pr.isSendSMS()? "sms": "mms") +" to";

addComponent (new MylistItem (MainMenuConstatns.MOVEMENT_NOTIFICATION,

new String[] {"Movement notification", msgType

+ pr.getMovNotification()}));

} else {

addComponent (new MylistItem (MainMenuConstatns.MOVEMENT_NOTIFICATION,

"Movement notification"));

}

if (pr.getErrNotificationNumber()!= "") {

addComponent (new MylistItem (MainMenuConstatns.ERROR_NOTIFICATION,

new String[] {"Error Notification", pr.getErrNotificationNumber()}));

} else {

addComponent (new MylistItem (MainMenuConstatns.ERROR_NOTIFICATION,

"Error Notification"));

}

addComponent (new MylistItem (MainMenuConstatns.CAMERA, "Camera"));

addComponent (new MylistItem (MainMenuConstatns.EXIT, "Exit"));

addComponent (new MylistItem (MainMenuConstatns.HELP, "Help"));

Обработка нажатия пользователем кнопок и определение, какая экранная форма должна быть показана далее, выполняется так, как показано в следующем листинге 3.6.

Листинг 3.6 - Обработка нажатий кнопок для главного меню

class MainMenuActionListener implements ActionListener {

public void actionPerformed (ActionEvent act) {

Component cmp = getFocused();

if (cmp instanceof MylistItem) {

int id = ((MylistItem) cmp).getId();

switch (id) {

case MainMenuConstatns.SCHEDULE:

midlet.getScheduleDisplay().show();

break;

case MainMenuConstatns.TRANSLATE_VIDEO:

midlet.getVideoTransmitionDisplay().show();

break;

case MainMenuConstatns.MOVEMENT_NOTIFICATION:

midlet.getMovementNotificationDisplay().show();

break;

case MainMenuConstatns.CAMERA:

midlet.getCamera().show();

midlet.getCamera().startCamera();

midlet.getCamera().revalidate();

break;

case MainMenuConstatns.EXIT:

midlet.exitMIDlet();

break;

case MainMenuConstatns.HELP:

midlet.getHelpScreen().show();

break;

case MainMenuConstatns.ERROR_NOTIFICATION:

midlet.getErrorNotification().show();

break;

}

}

}

На форме настройки расписания (рисунок 3.3) необходимо было реализовать динамическое скрытие / отображение некоторых элементов, а именно: когда выбирается радиокнопка enter time, то должны сразу под ней отобразиться поля для ввода часов, минут, дня, месяца, года. А при выборе радиокнопки unbounded эти поля должны быть скрыты.

62

Рисунок 3.3 - Заполнение расписания работы камеры

Такая функциональность реализуется путем указания у каждой радиокнопки ActionListener, который отслеживает выбор радиокнопок (листинг 3.7). dateFrom и dateTo являются контейнерами типа Container и содержат все необходимые поля для указания точной даты и времени.

Листинг 3.7 - Обработка выбора радиокнопок

public void actionPerformed (ActionEvent evt) {

Component cmp = (Component) evt.getSource();

if (cmp == rb1DateFromEnter) {

if (rb1DateFromEnter.isSelected()) {

if (! getContentPane().contains(dateFrom)) {

addComponent (3, dateFrom);

revalidate();

return;

}

}

}

if (cmp == rbDateFromUnbounded) {

if (getContentPane().contains(dateFrom)) {

removeComponent(dateFrom);

revalidate();

return;

}

}

if (cmp == rbDateToEnter) {

if (rbDateToEnter.isSelected()) {

if (! getContentPane().contains(dateTo)) {

addComponent (getContentPane().getComponentCount() - 2, dateTo);

dateTo.setFocus(true);

revalidate();

return;

}

}

}

if (cmp == rbDateToUnbounded) {

if (getContentPane().contains(dateTo)) {

removeComponent(dateTo);

revalidate();

return;

}

}

}

Рисунок 3.4 - Экранная форма со списком

Для всех списков в данном приложении разработан специальный способ их отображения - класс MyListCellRenderer. По умолчанию для отображения списков применяется DefaultListCellRenderer, который просто преобразовывает все элементы к объектам класса Label. Для создания своего способа отображения элементов списка необходимо реализовать интерфейс ListCellRenderer.

Метод getListCellRendererComponent этого интерфейса должен возвращать отображаемый элемент списка из объекта, передаваемого ему в качестве параметра. Переопределение методов getListFocusComponent обеспечивает возможность настройки стилей отображения выделенного и невыделенного элемента списка.

Пример списка, реализованного с помощью MyListCellRenderer, приведен на рисунке 3.4. В листинге 3.8 приведен программный код класса, который прорисовывает список.

Листинг 3.8 - Прорисовка списка

public class MyListCellRenderer extends Container implements ListCellRenderer {

public MyListCellRenderer() {

setLayout (new BoxLayout (BoxLayout.Y_AXIS));

}

/**

* Returns displayable list element from received object

*/

public Component getListCellRendererComponent (List list, Object value,

int index, boolean isSelected) {

if (value instanceof String) {

setText((String) value);

} else {

setText (value.toString());

}

setFocus(isSelected);

applyStyle (this, isSelected);

return this;

}

/**

* Applies style for selected and unselected element

*/

private void applyStyle (Component component, boolean isSelected) {

Style style = null;

if (isSelected) {

style = UIManager.getInstance().getComponentStyle ("_selected");

} else {

style = UIManager.getInstance().getComponentStyle ("_unselected");

}

component.setStyle(style);

}

public Component getListFocusComponent (List list) {

return null;

}

}

3.3 Передача данных по Bluetooth

API для работы с Bluetooth содержится в пакете JSR-82 [9]. Эта библиотека состоит из двух пакетов: базовое Bluetooth API и OBEX.

Для работы с Bluetooth у телефона должны быть минимум 512 килобайт памяти, а также поддерживаться CLDC.

Чтобы приложение могло использовать возможности Bluetooth, необходимо реализовать интерфейс DiscoveryListener и его методы deviceDiscovered(), inquiryCompleted(), servicesDiscovered(), serviceSearchCompleted(), используемые для обнаружения рядом находящихся Bluetooth-устройств.

Далее приводится программный код (листинг 3.9), который инициирует поиск. Вначале инициализируется переменная LocalDevice local, которая представляет собой данный телефон; потом инициализируется переменная DiscoveryAgent agent. Именно этот объект запускает поиск методом startInquiry() с параметрами DiscoveryAgent.GIAC и ссылкой на объект, который реализовал интерфейс DiscoveryListener и будет обрабатывать все события, связанные с обнаружением устройств и их сервисов. Этот метод возвращает true, если поиск устройств был успешно начат, или false в противном случае.

Переменная Vector devicesFound используется для сохранения всех обнаруженных устройств.

Листинг 3.9 - Начало поиска устройств

* This method starts device discovering

*/

public void doDeviceDiscovery() {

try {

local = LocalDevice.getLocalDevice();

} catch (BluetoothStateException bse) {

Log.out.println ("EXCEPTION!" + bse.toString());

}

agent = local.getDiscoveryAgent();

devicesFound = new Vector();

try {

if (! agent.startInquiry (DiscoveryAgent.GIAC, this)) {

Log.out.println (" DISCOVERING IS NOT STARTED");

}

} catch (BluetoothStateException bse) {

Log.out.println (" BluetoothStateException "+ bse.toString());

}

}

При обнаружении Bluetooth-устройства вызывается метод deviceDiscovered(), который получает в качестве параметров найденное устройство remoteDevice и его тип deviceClass.

Далее приводится программный код (листинг 3.10) этого метода. В методе выполняется добавление в список, отображаемый на экране, доступных рядом находящихся Bluetooth-устройств. Найденное устройство также добавляется в массив devicesFound.

Листинг 3.10 - Обработка события, связанного с обнаружением нового устройства

/**

* Called when a device is discovered during device discovery

* @param remoteDevice founded device

* @param deviceClass

public void deviceDiscovered (RemoteDevice remoteDevice,

DeviceClass deviceClass) {

try {

midlet.getSelectDeviceDisplay().getDevicesList().addItem (

remoteDevice.getFriendlyName(false));

devicesFound.addElement(remoteDevice);

} catch (IOException ex) {

Log.out.println ("ex when device has been discovered "+ex.toString());

}

}

После окончания поиска всех устройств вызывается метод inquiryCompleted(), в параметре которого содержится код результата поиска. Далее приводится этот метод (листинг 3.11).

Листинг 3.11 - Завершение поиска устройств

/**

* Called when device discovering is complete

* @param - param discovering status

public void inquiryCompleted (int param) {

midlet.getSelectDeviceDisplay().removeCommand (midlet.getSelectDeviceDisplay().

getStopSearchDevices());

midlet.getSelectDeviceDisplay().addCommand (midlet.getSelectDeviceDisplay().

getBackSelectDevice());

switch (param) {

case DiscoveryListener.INQUIRY_COMPLETED:

if (devicesFound.size() > 0) {

midlet.getSelectDeviceDisplay().removeCommand (

midlet.getSelectDeviceDisplay().getStopSearchDevices());

midlet.getSelectDeviceDisplay().addCommand (

midlet.getSelectDeviceDisplay().getBackSelectDevice());

doServiceSearch((RemoteDevice) devicesFound.elementAt(0));

} else

break;

case DiscoveryListener.INQUIRY_ERROR:

 //Error during inquiry

break;

case DiscoveryListener.INQUIRY_TERMINATED:

 // Inquiry terminated by agent.cancelInquiry()

break;

}

}

62

Рисунок 3.5 - Список найденных устройств

После поиска устройств (на рисунке 3.5 показан список обнаруженных устройств) начинается поиск сервисов на одном из них. Найденные сервисы запоминаются в массиве ServiceRecord[] servicesFound. В следующем листинге 3.12 приводится метод, который начинает поиск сервисов. Для начала поиска вызывается метод searchServices() ранее созданного объекта DiscoveryAgent agent, которому передаются следующие параметры: атрибуты искомого сервиса или его UUID, удаленное устройство, на котором производить поиск, а также ссылка на объект, который будет обрабатывать все события, связанные с обнаружением сервисов.

Листинг 3.12 - Инициация поиска сервисов

/**

* This method starts service search on the divice

* @param device to be scanned for services

public void doServiceSearch (RemoteDevice device) {

* Service search will always give the default attributes:

* ServiceRecordHandle (0x0000), ServiceClassIDList (0x0001),

* ServiceRecordState (0x0002), ServiceID (0x0003) and

* ProtocolDescriptorList (0x004).

* These hex-values must be supplied through an int array

*/

int[] attributes = null; // {0x100};

/*

* Supplying UUIDs in an UUID array enables searching for

* specific services.

UUID[] uuids = new UUID[1];

uuids[0] = new UUID(0x0003);

try {

agent.searchServices (attributes, uuids, device, this);

} catch (BluetoothStateException e) {

Log.out.println ("BluetoothStateException error" + e.getMessage());

}

}

Когда поиск сервисов завершен, вызывается метод serviceSearchCompleted(), код которого приведен ниже (листинг 3.13). В параметре данного метода содержится код результата поиска сервисов.

Листинг 3.13 - Завершение поиска сервисов

/**

* Called when service search completes

* @param transID identifies a particular service search

* @param respCode indicates why the service search is ended

*/

public void serviceSearchCompleted (int transID, int respCode) {

switch (respCode) {

case DiscoveryListener.SERVICE_SEARCH_COMPLETED:

Log.out.println ("serviceSearchCompleted: SERVICE_SEARCH_COMPLETED");

if (servicesFound.length > 0) {

midlet.getSelectDeviceDisplay().addCommand (

midlet.getSelectDeviceDisplay().getSelectDeviceCommand());

}

/*

* The service to connect to has been found earlier

* (by service discovery) and the service record is

* referencedthrough the object named: service (of type

* ServiceRecord)

*/

break;

case DiscoveryListener.SERVICE_SEARCH_DEVICE_NOT_REACHABLE:

Log.out.println ("serviceSearchCompleted: SERVICE_SEARCH_DEVICE_NOT_REACHABLE");

break;

case DiscoveryListener.SERVICE_SEARCH_ERROR:

Log.out.println ("serviceSearchCompleted: SERVICE_SEARCH_ERROR");

break;

case DiscoveryListener.SERVICE_SEARCH_NO_RECORDS:

Log.out.println ("serviceSearchCompleted: SERVICE_SEARCH_NO_RECORDS");

break;

case DiscoveryListener.SERVICE_SEARCH_TERMINATED:

Log.out.println ("serviceSearchCompleted: SERVICE_SEARCH_TERMINATED");

break;

}

}

Когда среди обнаруженных устройств выбрано одно и выполнен на нем поиск сервисов, то можно осуществить передачу данных по Bluetooth. Передача осуществляется через StreamConnection, URL которого получается с помощью следующего метода (листинг 3.14).

Листинг 3.14 - Получение URL для доступа к сервису

public String getServiceConnectionURL (int nom) {

if (nom < servicesFound.length) {

return servicesFound[nom].getConnectionURL (

ServiceRecord.NOAUTHENTICATE_NOENCRYPT,

false);

} else {

return null;

}

}

Следующий листинг 3.15 содержит код, который выполняет передачу данных. Метод sendImageViaBluetooth получает массив байт, который представляет собой изображение.

Листинг 3.15 - Отправка изображения по Bluetooth

public static void sendImageViaBluetooth (byte[] data) {

OutputStream btOutStr = null;

try {

StreamConnection conn = null;

String connectionURL = Preferences.getInstanse().getBTConnectionURL();

if (connectionURL == "") {

Log.out.println ("connectionURL is empty");

return;

}

try {

conn = (StreamConnection) Connector.open(connectionURL);

} catch (IOException e) {

Log.out.println (" sendImageViaBluetooth" + e.toString());

}

btOutStr = conn.openOutputStream();

btOutStr.write(data);

btOutStr.close();

} catch (IOException ex) {

Log.out.println ("sending image via BT failed (IOException)" + ex.toString());

} catch (Throwable th) {

Log.out.println ("sending image via BT failed" + th.toString());

} finally {

try {

btOutStr.close();

} catch (IOException ex) {

Log.out.println ("IOException while closing stream" + ex.toString());

}

}

}

Прием и отображение полученного кадра выполняется аналогичным способом на другом телефоне. Соответствующий код представлен в приложении А.

На следующем рисунке 3.6 приведен пример получения клиентом изображения по Bluetooth и отображения его на форме.

62

Рисунок 3.6 - Передача данных по Bluetooth

3.4 Работа с файловой системой телефона

В конфигурации CLDC отсутствует API для работы с файловой системой и внешними картами памяти телефона, т. к. не у каждого устройства с профилем MIDP есть файловая система.

Платформа J2SE включает в себя java.io. File и сопутствующие классы, но эти пакеты слишком тяжеловесны для мобильных устройств. Для работы с файлами в мобильных устройствах разработан пакет JSR-75 [10], который предоставляет простой и легковесный FileConnection API для работы с файловой системой. FileConnection API позволяет приложениям создавать, выполнять чтение и запись в файлы и директории, размещенные на телефоне или карте памяти. Основные классы и интерфейсы пакета JSR-75 следующие:

- интерфейс FileConnection - для доступа к файлам и директориям;

- интерфейс FileSystemListener - для прослушивания извещения о добавлении или удалении корневых директорий;

- класс FileSystemRegistry - центральный реестр для слушателей о добавлении или удалении корневых файловых систем;

- класс ConnectionClosedException - исключение, которое выбрасывается в случае невозможности выполнения методов FileConnection по причине закрытия соединения;

- класс IllegalModeException - исключение, которое выбрасывается в случае выполнения методов, требующих особых режимов безопасности, таких как READ или WRITE, но FileConnection открыт в другом режиме.

Приложение может открыть соединение, используя метод Connector.open(). Его единственный параметр - URL, содержащий полный путь к файлу специального формата: file:// <host>/<root>/<directory>/<directory>/…/<fileName>. Элемент host может быть пустым.

Список доступных корневых директорий устройства можно получить с помощью вызова метода FileSystemRegistry.listRoots().

Установив соединение FileConnection с файлом или каталогом, можно выполнять следующие действия:

- определять, куда указывает соединение FileConnection - на файл или папку - с помощью метода isDirectory();

- получать фильтрованный список файлов и директорий методом list (String filter, boolean includeHidden);

- проверять, существует ли директория или файл, применяя метод exists();

- определять, является ли скрытым файл, используя метод isHidden();

- создавать, удалять файл или директорию методами create(), mkdir() и delete();

- открывать входной / выходной поток для чтения / записи данных в файл, применяя методы openInputStream(), openOutputStream().

Листинг разработанного навигатора по файловой системе мобильного телефона представлен в приложении Б.

На рисунке 3.7 приведен пример отображения одного их каталогов файловой системы телефона.

62

Рисунок 3.7 - Файловый броузер

3.5 Отправка SMS и MMS-сообщений

Для отправки сообщений с мобильного телефона было использовано Wireless Messaging API 2.0 (пакет javax.wireless.messaging) [11]. Основные классы этого пакета следующие:

- MessageConnection - интерфейс, который определяет операции для посылки и получения сообщений;

- TextMessage - интерфейс, представляющий текстовые сообщения;

- MultipartMessage - интерфейс для представления составных сообщений;

- MessagePart - экземпляры данного класса могут быть добавлены в MultipartMessage. Каждый MessagePart состоит из данных.

Для отправки сообщений приложение должно сначала получить экземпляр MessageConnection, передав методу javax.microedition.io. Connector.open() URL, определяющий адресат. В этом URL содержится информация об используемом протоколе (SMS или MMS), номере телефона и порте адресата.

После создания MessageConnection формируется SMS или MMS-сообщение, заполняется данными и отправляется на указанный номер (листинги 3.16 и 3.17).

Листинг 3.16 - Отправка SMS-сообщений

* Send SMS with specified text to phoneNumber

public static void sendSMS (String phoneNumber, String text) {

try {

String addr = "sms:// " + phoneNumber+":5678";

MessageConnection conn = (MessageConnection) Connector.open(addr);

TextMessage msg = (TextMessage) conn.newMessage (MessageConnection.TEXT_MESSAGE);

msg.setPayloadText(text);

conn.send(msg);

conn.close();

} catch (IOException ex) {

Log.out.println ("IOException at Utilities.sendSMS()" + ex.toString());

}

}

Листинг 3.17 - Отправка MMS-сообщений

* Send MMS with specified image in second parameter to phoneNumber

*/

public static void sendMMS (String phoneNumber, byte[] data) {

try {

private static MessageConnection conn;

private static MultipartMessage msg;

String addr = "mms:// " + phoneNumber +":5432";

conn = (MessageConnection) Connector.open(addr);

msg = (MultipartMessage) conn.newMessage (MessageConnection.MULTIPART_MESSAGE);

 // size of the part and the number of bytes loaded to mms

int partSize = 10000, counter = 0;

byte buf[] = new byte[partSize];

for (int i = 0; i < data.length / partSize && counter<=290000; i++) {

int curPartLength = partSize;

 // if the number of left bytes in data[] is lenss then part size

if (counter + partSize > data.length) {

buf = new byte [data.length - counter];

curPartLength = data.length - counter;

}

 // load next part of mms

for (int j = 0; j < curPartLength; j++) {

buf[j] = data [counter++];

}

MessagePart p = new MessagePart (

buf,

Preferences.getInstanse().getEncodingType(),

String.valueOf(i), null, null);

msg.addMessagePart(p);

}

} catch (SizeExceededException ex) {

Log.out.print ("SizeExceededException "+ex.toString());

} catch (Exception e) {

Log.out.print ("Exception "+e.toString());

} finally {

try {

conn.send(msg);

conn.close();

} catch (IOException ex) {

Log.out.print ("IOException "+ex.toString());

}

}

}

Для указания номера, на который необходимо отправлять сообщения с уведомлениями об обнаруженном движении или о возможных ошибках в работе, разработаны две формы (рисунок 3.8).

62

62

Рисунок 3.8 - Настройка SMS и MMS-уведомлений

3.6 Алгоритм обнаружения движения

Алгоритм обнаружения движения основан на сравнении последовательных кадров, которые получаются от камеры с использованием Mobile Media API [12] следующим образом (листинг 3.18).

Листинг 3.18 - Доступ к камере

 // get access to camera

player = Manager.createPlayer ("capture://video");

player.realize();

videoControl = (VideoControl) getPlayer().getControl ("VideoControl");

videoControl.setDisplayFullScreen(true);

byte[] b = new byte[5000];

 // get snapshot

b = videoControl.getSnapshot(encodings);

im = Image.createImage (b, 0, b.length);

rgbIm = new RGBImage(im);

 // call method for motion detection

int r = process (rgbIm.getRGB());

На рисунке 3.9 приведена диаграмма деятельности, которая описывает процесс видеонаблюдения.

Функция обнаружения движения получает в качестве параметра очередной кадр камеры, который представляет собой одномерный массив. Каждый элемент массива - это одна точка изображения в формате AARRGGBB, который обозначает следующее:

- AA - прозрачность (0xFF означает полную непрозрачность, а 0 - полную прозрачность);

- RR, GG, BB - соответственно красная, зеленая, голубая rgb-составляющие цвета данной точки.

Обнаружение движения выполняется в несколько этапов. На первом сравниваются два последовательных кадра и формируется маска. Для этого подсчитывается средняя прозрачность всех точек двух сравниваемых кадров и определяется их разность (коррекция). Далее происходит сравнение соответствующих точек этих кадров и вычисляются разности rgb-составляющих цветов этих точек (листинг 3.19).

Эти разности затем корректируются, а именно: присваивается 0, если данная разность меньше коррекции, в противном случае - из данной разности вычитают коррекцию. Далее получают оттенок серого по скорректированным rgb-разностям, как показано в листинге 3.19 (вычисление переменной result). В результирующую маску записывается этот оттенок серого с учетом прозрачности alpha, взятой из соответствующей точки предыдущего кадра. Если в данных точках есть значительное изменение, то в маску записывается белая точка.

Листинг 3.19 - Формирование маски

 // ip is a element number in two arrays -

 // current image (inDataInt) and the previous one (refDataInt)

int alpha = refData[ip] & 0xFF000000;

refDataInt = (refData[ip] & 0xFF0000) / 256 / 256;

inDataInt = (inData[ip] & 0xFF0000) / 256 / 256;

r = (refDataInt > inDataInt)? refDataInt - inDataInt: inDataInt - refDataInt;

refDataInt = (refData[ip] & 0x00FF00) / 256;

inDataInt = (inData[ip] & 0x00FF00) / 256;

g = (refDataInt > inDataInt)? refDataInt - inDataInt: inDataInt - refDataInt;

refDataInt = (refData[ip] & 0x0000FF);

inDataInt = (inData [ip++] & 0x0000FF);

b = (refDataInt > inDataInt)? refDataInt - inDataInt: inDataInt - refDataInt;

 // intensity normalization

r -= (r < correction)? r: correction;

g -= (g < correction)? g: correction;

b -= (b < correction)? b: correction;

result = (byte) (java.lang. Math.sqrt((double) ((r * r) + (g * g) + (b * b)) / 3.0));

 // bwData is a mask

if (result > (byte) threshold) {

bwData [op++] = alpha + 0xFFFFFF;

} else {

bwData [op++] = alpha + result;

}

Далее анализируется полученная маска и подсчитывается количество областей, где рядом находящиеся точки красного цвета. На рисунке 3.10 показаны рядом находящиеся точки (отмечены символом "v") около текущей (обведена толстой линией). Если количество таких областей больше некоторого порога, то движение было обнаружено.

v

v

v

v

v

v

v

v

v

Рисунок 3.10 - Анализ маски

Полный листинг метода обнаружения движения приведен в приложении В.

Рисунок 3.9 - Диаграмма деятельности для процесса видеонаблюдения

Заключение

В дипломной работе освещены теоретические основы платформы J2ME, архитектуры Bluetooth и обработка видеоданных для обнаружения движения. Разработано приложение на платформе J2ME, которое позволяет осуществлять видеонаблюдение. В нем используются такие ресурсы мобильного телефона как файловая система, камера, Bluetooth, отправка SMS и MMS-сообщений. Изучена библиотека LWUIT, применяемая для построения графического интерфейса.

Приложение состоит из двух мидлетов, устанавливаемых на разных телефонах, один из которых выполняет видеонаблюдение и передает данные по Bluetooth, а второй эти данные принимает.

Для первого мидлета предусмотрена возможность отправки на указанный номер SMS и MMS-сообщений с уведомлением о движении, а также сообщений о возможных ошибках. Приложение имеет встроенный броузер файловой системы и позволяет выбирать папку для сохранения данных камеры в виде отдельных изображений. Включение камеры для обнаружения движения и ее отключение может быть выполнено по заранее определенному расписанию.

Второй мидлет принимает изображения, показывает их и сохраняет на телефоне.

Интерфейс данного приложения реализован с помощью библиотеки LWUIT. Для отправки SMS и MMS-сообщений с мобильного телефона использовалось Wireless Messaging API 2.0 (JSR-205). Работа с файловой системой построена на основе FileConnection API (JSR-75). Передача данных по Bluetooth реализована с помощью пакета JSR-82. Доступ к камере выполнен с помощью MobileMedia API (JSR-135).

Полученные результаты докладывались на XII Республиканской научной конференции студентов и аспирантов "Новые математические методы и компьютерные технологии в проектировании, производстве и научных исследованиях". Опубликованы тезисы доклада [13].

Список использованных источников

Официальный сайт компании Sun Microsystems. Платформа Java 2 Micro Edition [Электронный ресурс] / Режим доступа: http://java.sun.com/javame/reference/apis.jsp. - Дата доступа: 25.05.2009.

Горнаков С.Г. Программирование мобильных телефонов на Java 2 Micro Edition / С.Г. Горнаков. - М.: ДМК Пресс, 2004. - 336 с.

Пирумян B.В. Платформа программирования J2ME для портативных устройств / B.В. Пирумян Пер. с англ. - М.: КУДИЦ-ОБРАЗ, 2002. - 352 с.

Статьи разработчиков LWUIT [Электронный ресурс] / Режим доступа: http://lwuit.blogspot.com/ - Дата доступа: 25.05.2009.

Официальный сайт библиотеки LWUIT Edition [Электронный ресурс] / Режим доступа: https://lwuit.dev.java.net/ - Дата доступа: 25.05.2009;

Архипкин В.Я. Bluetooth. Технические требования. Практическая реализация / В.Я. Архипкин, А.В. Архипкин. - М.: Мобильные коммуникации, 2004. - 203 с.

Вишневский В.М Широкополосные беспроводные сети передачи информации / В.М Вишневский, А.И. Ляхов, С.Л. Портной. - М.: Эко-Трендз, 2005. - 592 с.

Andre N. Klingsheim, J2ME Bluetooth Programming, 2004.

Спецификация Bluetooth API and OBEX API (JSR-82) for Java Platform, Micro Edition.

Спецификация FileConnection Optional Package (JSR-75) for Java 2 Micro Edition Version 1.0.

Спецификация Wireless Messaging API (JSR-205) for Java 2 Micro Edition Version 1.1.

Спецификация Mobile Media API (JSR-135) for Java 2 Micro Edition.

Лусканова М.В. Организация видеонаблюдения с помощью мобильного телефона / М.В. Лусканова, Е.А. Ружицкая // "Новые математические методы и компьютерные технологии в проектировании, производстве и научных исследованиях", XII Республиканская научная конференция студентов и аспирантов (2009, Гомель)

Страницы: 1, 2


© 2010 РЕФЕРАТЫ