В этот раз речь пойдет об использовании сервиса Connection Manager, который позволяет определить состояние подключения к сети. В WebOS существует возможность узнать состояние подключения к:

  • Bluetoot
  • Wi-Fi
  • WAN

Использовать сервис Connection Manager можно как для одноразового получения состояния сетевых подключений, так и для подписки на уведомление об изменении состояния подключений.Для определения текущего состояния сетевых соединений необходимо вызвать метод serviceRequest() объекта-контроллера, в который передать идентификатор сервиса Connection Manager, а также JSON-объект с параметрами вызова сервиса. Параметры вызова сервиса могут быть такими:

  • method – обязательный параметр. У сервиса Connection Manager есть всего один метод – getstatus.
  • parameters – JSON-объект, который будет передан в качестве параметра методу getstatus. У этого объекта есть одно значимое булевое свойство – subscribe. Если свойство subscribe имеет значение true, то будет выполнена подписка на уведомления об изменении состояния подключений. При каждом изменении состояния будет вызвана наша callback-функция.
  • onSuccess – callback-функция, вызываемая при успешном завершении запроса состояния подключений.
  • onFailure – callback-функция, вызываемая если запрос состояния подключений завершился с ошибкой.

Пример вызова Connection Manager

this.controller.serviceRequest('palm://com.palm.connectionmanager', {
    method: 'getstatus',
    parameters: {subscribe:true},
    onSuccess: this.handleOKResponse.bind(this),
    onFailure: this.handleErrResponse
});

Теперь рассмотрим более детально callback-функции, вызываемые при завершении запроса состояния соединения.

onSuccess

Callback-функция onSuccess принимает в качестве параметра объект, содержащий информацию о состоянии подключений. Этот объект содержит такие поля:

Свойство Тип Описание
errorCode integer Код завершения операции проверки статуса подключения.
errorText string Описание ошибки если errorCode содержит ненулевое значение.
isInternetConnectionAvailable boolean Содержит значение true если есть подключение к Internet.
returnValue boolean true если была выполнена подписка на уведомление об изменении состояния подключений. Может быть получено только первый раз при выполнении подписки.
wifi object Содержит информацию о подключении к Wi-Fi.
btpan object Содержит информацию о подключении к Bluetooth.
wan object Содержит информацию о подключении к WAN.

Теперь посмотрим что можно узнать о подключениях:

Свойства объекта btpan
Свойство Тип Описание
ipAddress string IP-адрес в сети Bluetooth PAN.
panUser string Содержит название клиента сети Bluetooth PAN, подключенного к устройству.
state string Имеет значение “connected” если соединение есть и “disconnected” если соединения нет.
Свойства объекта wifi
Свойство Тип Описание
bssid string Basic service set identifier (BSSID) точки доступа.
ipAddress string IP-адрес в сети Wi-Fi.
ssid string Service set identifier (BSSID) точки доступа.
state string Имеет значение “connected” если соединение есть и “disconnected” если соединения нет.
Свойства объекта wan
Свойство Тип Описание
ipAddress string IP-адрес в сети WAN.
network string Сожет иметь значения: “unknown”, “unusable”, “gprs”, “edge”, “umts”, “hsdpa”, “1x”, or “evdo.”
Внимание: значение “unusable” используется в случае если интерфейс WAN подключен, но данніе не могут быть отправлены или получены по каким-либо причинам.
state string Имеет значение “connected” если соединение есть и “disconnected” если соединения нет.

onFailure

Callback-функция onFailure принимает в качетве параметра объект, содержащий информацию об ошибке. Свойства этого объекта приведены ниже:

Свойство Тип Описание
errorCode string Строка, содержащая код ошибки:

  1. Неизвестная ошибка.
  2. Ошибка подписки на уведомления о состоянии соединения.
errorText string Строка, содержащая описание ошибки.
returnValue boolean false

Пример использования

С теоретической частью мы закончили. Теперь рассмотрим пример.

Создадим новый проект и в нем сцену с названием first.

app/views/first/first-scene.html

<div id="SubscribeButton" x-mojo-element="Button"></div>
<div id="area-to-update"></div>
<div class="palm-inline-error" style="display:none" id="ErrorMessage">
<div class="error-message">Unable to subscribe to Connection Manager's event.</div>
</div>

<div class="palm-group">
  <div class="palm-group-title">Wi-Fi</div>
  <div class="palm-list">
    <div class="palm-row first">
      <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
        <div class="title">
          <div class="label">IP Address</div>
          <div id="WiFiIPTextBox" x-mojo-element="TextField"></div>
        </div>
      </div>
    </div>
    <div class="palm-row">
      <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
        <div class="title">
          <div class="label">BSSID</div>
          <div id="WiFiBSSIDTextBox" x-mojo-element="TextField"></div>
        </div>
      </div>
    </div>
    <div class="palm-row">
      <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
        <div class="title">
          <div class="label">SSID</div>
          <div id="WiFiSSIDTextBox" x-mojo-element="TextField"></div>
        </div>
      </div>
    </div>
    <div class="palm-row last">
      <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
        <div class="title">
          <div class="label">State</div>
          <div id="WiFiStateTextBox" x-mojo-element="TextField"></div>
        </div>
      </div>
    </div>
  </div>
</div>

<div class="palm-group">
  <div class="palm-group-title">Bluetooth</div>
  <div class="palm-list">
    <div class="palm-row first">
      <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
        <div class="title">
          <div class="label">IP Address</div>
          <div id="BTPanIPTextBox" x-mojo-element="TextField"></div>
        </div>
      </div>
    </div>
    <div class="palm-row">
      <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
        <div class="title">
          <div class="label">User</div>
          <div id="BTPanUserTextBox" x-mojo-element="TextField"></div>
        </div>
      </div>
    </div>
    <div class="palm-row last">
      <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
        <div class="title">
          <div class="label">State</div>
          <div id="BTPanStateTextBox" x-mojo-element="TextField"></div>
        </div>
      </div>
    </div>
  </div>
</div>

<div class="palm-group">
  <div class="palm-group-title">WAN</div>
  <div class="palm-list">
    <div class="palm-row first">
      <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
        <div class="title">
          <div class="label">IP Address</div>
          <div id="WanIPTextBox" x-mojo-element="TextField"></div>
        </div>
      </div>
    </div>
    <div class="palm-row">
      <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
        <div class="title">
          <div class="label">Network</div>
          <div id="WanNetworkTextBox" x-mojo-element="TextField"></div>
        </div>
      </div>
    </div>
    <div class="palm-row last">
      <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
        <div class="title">
          <div class="label">State</div>
          <div id="WanStateTextBox" x-mojo-element="TextField"></div>
        </div>
      </div>
    </div>
  </div>
</div>

app/assistants/first-assistant.js

function FirstAssistant() {
}

FirstAssistant.prototype.setup = function() {
    this.controller.setupWidget('SubscribeButton', {}, {label:'Subscribe'});
    this.controller.setupWidget("BTPanIPTextBox",
        {
            modelProperty: 'originalValue'
        },
        this.btpanIPModel =
        {
            originalValue: '',
            disabled: true
        });
    this.controller.setupWidget("BTPanUserTextBox",
        {
            modelProperty: 'originalValue'
        },
        this.btpanUserModel =
        {
            originalValue: '',
            disabled: true
        });
    this.controller.setupWidget("BTPanStateTextBox",
        {
            modelProperty: 'originalValue'
        },
        this.btpanStateModel =
        {
            originalValue: '',
            disabled: true
        });

    this.controller.setupWidget("WiFiIPTextBox",
        {
            modelProperty: 'originalValue'
        },
        this.wifiIPModel =
        {
            originalValue: '',
            disabled: true
        });
    this.controller.setupWidget("WiFiBSSIDTextBox",
        {
            modelProperty: 'originalValue'
        },
        this.wifiBSSIDModel =
        {
            originalValue: '',
            disabled: true
        });
    this.controller.setupWidget("WiFiSSIDTextBox",
    {
            modelProperty: 'originalValue'
        },
        this.wifiSSIDModel =
        {
            originalValue: '',
            disabled: true
        });
    this.controller.setupWidget("WiFiStateTextBox",
        {
            modelProperty: 'originalValue'
        },
        this.wifiStateModel =
        {
            originalValue: '',
            disabled: true
        });

    this.controller.setupWidget("WanIPTextBox",
        {
            modelProperty: 'originalValue'
        },
        this.wanIPModel =
        {
            originalValue: '',
            disabled: true
        });
    this.controller.setupWidget("WanNetworkTextBox",
        {
            modelProperty: 'originalValue'
        },
        this.wanNetworkModel =
        {
            originalValue: '',
            disabled: true
        });
    this.controller.setupWidget("WanStateTextBox",
        {
            modelProperty: 'originalValue'
        },
        this.wanStateModel =
        {
            originalValue: '',
            disabled: true
        });

    Mojo.Event.listen(this.controller.get('SubscribeButton'),
        Mojo.Event.tap, this.handleSubscribeButton.bind(this));
}

FirstAssistant.prototype.handleSubscribeButton = function(){
    this.controller.serviceRequest('palm://com.palm.connectionmanager', {
        method: 'getstatus',
        parameters: {subscribe:true},
        onSuccess: this.handleOKResponse.bind(this),
        onFailure: this.handleErrResponse
    });
}

FirstAssistant.prototype.handleOKResponse = function(response){
    this.controller.get('ErrorMessage').hide();
    this.controller.get('ErrorMessage').setStyle({visibility:'hidden'});

    this.btpanStateModel.originalValue = response.btpan.state;
    this.btpanIPModel.originalValue = response.btpan.ipAddress;
    this.btpanUserModel.originalValue = response.btpan.panUser;
    this.controller.modelChanged(this.btpanStateModel);
    this.controller.modelChanged(this.btpanIPModel);
    this.controller.modelChanged(this.btpanUserModel);

    this.wifiStateModel.originalValue = response.wifi.state;
    this.wifiIPModel.originalValue = response.wifi.ipAddress;
    this.wifiSSIDModel.originalValue = response.wifi.ssid;
    this.wifiBSSIDModel.originalValue = response.wifi.bssid;
    this.controller.modelChanged(this.wifiStateModel);
    this.controller.modelChanged(this.wifiIPModel);
    this.controller.modelChanged(this.wifiSSIDModel);
    this.controller.modelChanged(this.wifiBSSIDModel);

    this.wanStateModel.originalValue = response.wan.state;
    this.wanIPModel.originalValue = response.wan.ipAddress;
    this.wanNetworkModel.originalValue = response.wan.network;
    this.controller.modelChanged(this.wanStateModel);
    this.controller.modelChanged(this.wanIPModel);
    this.controller.modelChanged(this.wanNetworkModel);
}

FirstAssistant.prototype.handleErrResponse = function(response){
    this.controller.get('ErrorMessage').show();
    this.controller.get('ErrorMessage').setStyle({visibility:'visible'});
}

FirstAssistant.prototype.cleanup = function(event) {
    Mojo.Event.stopListening(this.controller.get("SubscribeButton"),
        Mojo.Event.tap, this.handleSubscribeButton);
}

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

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

WebOS Connection Manager Test

В обработчике onSuccess мы получаем значения всех полей из объектов wan, wifi и btpan и отображаем их в соответствующих текстовых полях.

В эмуляторе валидной будет информация только о подключении к Wi-Fi. Другие сетевые подключения на данный момент не доступны под эмулятором.

Скачать исходный код примера.

Previous ArticleNext Article
Технический директор IT-Dimension, компании-разработчика кросс-платформенного программного обеспечения

Leave a Reply

Your email address will not be published. Required fields are marked *

П.

Пишем для Palm WebOS “на коленке”, создаем проект руками

В этот раз рассмотрим более детально структуру приложения для WebOS. В SDK есть достаточное количество дополнительных утилит, кторые могут помочь сгенерировать приложение или сцену. Но, при использовании автоматических кодогенераторов, понимания того, как же всетаки устроен проект, не прибавляется. Если кодогенератор отработает некорректно по какой-либо причине, без знания структуры проекта вернуть все в рабочее состояние будет непросто.

Для начала сделаем вот что: создадим пустой проект. В Eclipse идем в File -> New -> Other, в диалоговом окне выбираем General -> Project. Далее в мастере указываем имя проекта и путь, где он будет создан.

Создаем файл описания приложения

Создаем пустой файл в проекте, называем его appinfo.json

{
	"id": "com.itdimension.manuallycreatedwebosproject",
	"version": "1.0.0",
	"vendor": "Mobile-Developer.ru",
	"type": "web",
	"main": "index.html",
	"title": "Manually Created Project",
	"icon": "icon.png"
}

В этом файле указаны:

  • id – уникальный идентификатор приложения
  • version – версия приложения
  • vendor – название производителя
  • type – тип проекта
  • main – начальная страница приложения
  • title – название проекта (оно будет использовано для отображения в списке установленных  приложений WebOS)
  • icon – иконка приложения (также будет использоваться при отображении в Launcher’е)

Как видно, файл настроек приложения содержит упоминание двух файлов – файла главной страницы, а также иконки приложения. Узнать больше о параметрах, которые можно указать в appinfo.js можно здесь. Интересным также является тот факт, что кроме web-приложений можно создавать и нативные приложения. Для таких приложений свойство type будет иметь значение native.

Создаем файл главной страницы

В проекте Eclipse создаем новый html-файл, называем его index.html.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
	"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
	<title>CameraTest</title>
	<script 
		src="/usr/palm/frameworks/mojo/mojo.js" 
		type="text/javascript" x-mojo-version="1" />
	<link
		href="stylesheets/cameratest.css" 
		media="screen" rel="stylesheet" type="text/css" />
</head>
<body>
	<h2>Manually Created Project</h2>
</body>
</html>

Если в приложении будут использоваться нестандартные CSS-стили элементов управления, то они должны быть указаны обязательно ПОСЛЕ ссылки на mojo.js.

И вот, в данный момент у нас есть каркас минимального приложения, которое можно запустить на эмуляторе. Но прежде чем его запустить, нужно создать пакет, который будет установлен на эмулятор (или на устройство).

Для создания пакета в Palm Mojo SDK есть скрипт palm-package. Нам достаточно скормить этому скрипту путь к папке с проектом и на выходе получим .ipk файл с приложением.

palm-package ManuallyCreatedWebOSProject

В результате выполнения этой команды у нас должен получиться файл com.itdimension.manuallycreatedwebosproject_1.0.0_all.ipk
Для того чтобы загрузить пакет на эмулятор необходимо вызвать скрипт palm-install и скормить ему .ipk файл

D:\Projects\Eclipse Projects>palm-install com.itdimension.manuallycreatedwebosproject_1.0.0_all.ipk

После этого в эмуляторе запускаем Launcher и видим в нем наше приложение.
WebOS Manually Created Application in Launcher
После запуска приложения получим вот такой экран:
WebOS Manually Created App
Теперь надо бы сделать так, чтобы в нашем приложении кроме главной страницы было еще что-нибудь.

Создаем сцену

Для начала надо создать структуру каталогов:

  • app
    • assistants – в ней юудут находиться js-файлы, содержащие логику управления сценами
    • views – в ней будут содержаться html-файлы сцен

В WebOS-приложении есть понятие “stage” – окно и “scene” – панель в окне. Для каждой сущности нужен свой assistant-класс с обработчиками событий.

stage-assistant.js

function StageAssistant() {
}

StageAssistant.prototype.setup = function() {
    this.controller.pushScene("main");
}

Как видим, в конструкторе assistant-класса мы отображаем сцену с именем main. Теперь создадим саму сцену:

В папке views создаем папку main и в ней файл main-scene.html

<div id="main" class="palm-hasheader">
    <div class="palm-header">Camera Test</div>
    <div id="MyButton" x-mojo-element="Button"></div>
</div>

В папке assistants создаем main-assistant.js

function MainAssistant() {
}

MainAssistant.prototype.setup = function() {
	this.controller.setupWidget("MyButton", {}, {label:"My Button"});
}

Теперь создадим файл sources.json, в котором будут регистрироваться файлы с assistant-классами.

[
    {"source": "app\/assistants\/stage-assistant.js"},
    {
        "source": "app\/assistants\/main-assistant.js",
        "scenes": "main"
    }
]

В результате после запуска приложения получим такой пользовательский интерфейс:
WebOS Manually Created Scene

Скачать исходный код примера.

П.

Полноэкранный режим работы приложений в Palm WebOS

Работа в полноэкранном режиме на мобильном устройстве – полезная штука, особенно если вы пишете что-нибудь эдакое, например игру. Размер экрана и так небольшой, а панель состояния отбирает у приложения таоке драгоценное пространство.

WebOS позволяет приложениям работать в полноэкранном режиме. Вот об этой возможности мы и узнаем подробнее в этот раз.Итак, у нас задача – сделать приложение, работающее в полноэкранном режиме.

Создаем новый проект и в нем две сцены – main и fullscreen.

app/views/main/main-scene.html

<div class="palm-hasheader">
  <div class="palm-header">FullScreen Test</div>
</div>
<div class="palm-header-spacer"></div>
<div id="FullScreenSceneButton" x-mojo-element="Button"></div>
<div id="ExitButton" x-mojo-element="Button"></div>

app/assistants/main-assistant.js

function MainAssistant() {
}

MainAssistant.prototype.setup = function() {
    this.controller.setupWidget("FullScreenSceneButton", {}, {label: "FullScreen Scene"});
    this.controller.setupWidget("ExitButton", {}, {label: "Exit"});

    Mojo.Event.listen($(FullScreenSceneButton), Mojo.Event.tap, this.onFullScreen.bind(this));
    Mojo.Event.listen($(ExitButton), Mojo.Event.tap, this.onExit.bind(this));
}

MainAssistant.prototype.onFullScreen = function(event) {
    this.controller.stageController.pushScene("fullscreen");
}

MainAssistant.prototype.onExit = function(event) {
    this.controller.stageController.getAppController().closeAllStages();
    window.close();
}

MainAssistant.prototype.cleanup = function(event) {
    Mojo.Event.stopListening($(FullScreenSceneButton), Mojo.Event.tap, this.onFullScreen);
    Mojo.Event.stopListening($(ExitButton), Mojo.Event.tap, this.onExit);
}

На нашей сцене – заголовок и две кнопки. Первая – открывает сцену fullscreen, а вторая – закрывает приложение.

app/views/fullscreen/fullscreen-scene.html

<div class="palm-group">
  <div class="palm-group-title">Sample Fullscreen Scene</div>
</div>
<div id="PopButton" x-mojo-element="Button"></div>

Для перехода в полноэкранный режим у контроллера сцены есть метод enableFullScreenMode(), который принимает булевый параметр и благодаря которому тот же метод служит и для включения и для выключения полноэкранного режима.

app/assistants/fullscreen-assistant.js

function FullscreenAssistant() {
}

FullscreenAssistant.prototype.setup = function() {
    this.controller.setupWidget("PopButton", {}, {label: "Close"});
    Mojo.Event.listen($(PopButton), Mojo.Event.tap, this.onClose.bind(this));
}

FullscreenAssistant.prototype.activate = function(event) {
    this.controller.enableFullScreenMode(true);
}

FullscreenAssistant.prototype.onClose = function(event) {
    this.controller.stageController.popScene();
}

FullscreenAssistant.prototype.deactivate = function(event) {
    this.controller.enableFullScreenMode(false);
}

FullscreenAssistant.prototype.cleanup = function(event) {
    Mojo.Event.stopListening($(PopButton), Mojo.Event.tap, this.onClose);
}

Активацию полноэкранного режима нужно делать при активации сцены, а выход из полноэкранного режима – при деактивации сцены. Не надо переходить в полноэкранный режим внутри метода setup(). Из-за этого можно получить артефакты отрисовки. По этому поводу можно найти достаточно информации на официальном форуме WebOS-разработчиков. В общем, activate() и deactivate() – это как раз подходящие методы для этого.

После всего получаем такой вот результат (скрин из эмулятора):

WebOS Fullscreen

Скачать исходный код примера.