В WebOS пользователь может вручную указать интервал, по истечению которого, если устройство не используется, оно переходит в спящий режим. Этот интервал может варьироваться вдиапазоне от 30 секунд до 3х минут.

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

Итак, нам понадобится тестовое приложение. Создаем проект и в нем сцену main.

app/views/main/main-scene.html

<div class="palm-hasheader">
  <div class="palm-header">Power Management Test</div>
</div>
<div class="palm-header-spacer"></div>
<div id="TimeoutPicker" x-mojo-element="IntegerPicker"></div>
<div id="StartActivityButton" x-mojo-element="Button"></div>
<div id="StopActivityButton" x-mojo-element="Button"></div>
<div id="ExitButton" x-mojo-element="Button"></div>
<div id="info" class="palm-body-text"></div>

Сцена содержит виджет для выбора таймаута, в течении которого устройство не должно засыпать, а также кнопки:

  • Переход в активносе состояние
  • Выход из активного состояния
  • Выход из приложения

app/assistants/main-assistant.js

function MainAssistant() {
}

MainAssistant.prototype.setup = function() {
    this.controller.setupWidget("TimeoutPicker",
        {
            modelProperty: 'value',
            label: 'Timeout (minutes)',
            min: 01,
            max: 15,
            padNumbers: true
        },
        this.timeoutModel =
        {
            value: 1
        });
    this.controller.setupWidget("StartActivityButton", {},
        this.startButtonModel = {label: "Start Activity"});
    this.controller.setupWidget("StopActivityButton", {},
        this.stopButtonModel = {label: "Stop Activity", disabled: true});
    this.controller.setupWidget("ExitButton", {}, {label: "Exit"});

    Mojo.Event.listen($(StartActivityButton), 
        Mojo.Event.tap, this.onStartActivity.bind(this));
    Mojo.Event.listen($(StopActivityButton), 
        Mojo.Event.tap, this.onStopActivity.bind(this));
    Mojo.Event.listen($(ExitButton), Mojo.Event.tap, this.onExit.bind(this));

    this.counter = 0;
}

MainAssistant.prototype.onStartActivity = function(event) {
}

MainAssistant.prototype.onStopActivity = function() {
}

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

MainAssistant.prototype.cleanup = function(event) {
    Mojo.Event.stopListening($(StartActivityButton), Mojo.Event.tap, this.onStartActivity);
    Mojo.Event.stopListening($(StopActivityButton), Mojo.Event.tap, this.onStopActivity);
    Mojo.Event.stopListening($(ExitButton), Mojo.Event.tap, this.onExit);
}

В результате получим такой внешний вид приложения:

WebOS Power Management Sample Application

Теперь можно писать логику для обработчиков событий.

Для запуска активного режима приложения необходимо вызвать метод activityStart сервиса palm://com.palm.power/com/palm/power.

MainAssistant.prototype.onStartActivity = function(event) {
    this.counter++;
    this.activity = /* "com.palm.app."  + */
        Mojo.appName + ".activity-" + this.counter;
    this.controller.serviceRequest("palm://com.palm.power/com/palm/power",
    {
         method: "activityStart",
         parameters:
         {
             id: this.activity,
             duration_ms: this.timeoutModel.value * 60 * 1000
         },
         onSuccess: this.activityStartSuccess.bind(this),
         onFailure: this.activityStartFailure.bind(this)
        });
    this.timer = setTimeout(this.onTimer.bind(this),
        this.timeoutModel.value * 60 * 1000 / 2.0);
}

MainAssistant.prototype.onTimer = function(event) {
    if(this.timer)
    {
        clearTimeout(this.timer);
        delete this.timer;
    }
    this.onStopActivity();
}

MainAssistant.prototype.activityStartSuccess = function(event) {
    this.startButtonModel.disabled = true;
    this.stopButtonModel.disabled = false;
    this.controller.modelChanged(this.startButtonModel);
    this.controller.modelChanged(this.stopButtonModel);
    $(info).update("Activity started: " + this.activity);
}

MainAssistant.prototype.activityStartFailure = function(event) {
    $(info).update("Error:<br>" + Object.toJSON(event));
}

Параметры метода activityStart:

  • id – уникальный идентификатор вызова активного режима (можно использовать формат ID-приложения + ID-операции + счетчик).
  • duration_ms – длительность активного режима в миллисекундах. Максимальное значение єтого параметра 900000, что соответствует 15ти минутам.

Возможные проблемы:

  • На эмуляторе вызов activityStart не дает видимого эффекта. Виртуальная машина остается активной всегда.
  • На официальном форуме разработчиков WebOS-приложений неоднократно появлялась информация о том, что активный режим работает только для системных приложений (с идентификатором, начинающимся на com.palm.app). Также была информация что эту проблему исправили и активный режим доступен для разработчиков сторонних приложений, но без устройства это подтвердить нет никакой возможности.
  • По окончанию активного режима приложение не получает никаких уведомлений, и в случае, когда активный режим завершился, а приложение все еще должно держать устройство включенным, надо перезапускать активный режим заново, указывая новый идентификатор вызова. В таком случае очень удобно пользоваться счетсиком. Для того, чтобы вовремя продлить активный режми, можно использовать таймер.

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

MainAssistant.prototype.onStopActivity = function() {
    if(this.activity)
    {
        this.controller.serviceRequest("palm://com.palm.power/com/palm/power", {
             method: "activityEnd",
             parameters:
             {
                 id: "com.palm.app.news.update-1"
             },
             onSuccess: this.activityStopSuccess.bind(this),
             onFailure: this.activityStopFailure.bind(this)
        });
    }
}

MainAssistant.prototype.activityStopSuccess = function(event) {
    this.startButtonModel.disabled = false;
    this.stopButtonModel.disabled = true;
    this.controller.modelChanged(this.startButtonModel);
    this.controller.modelChanged(this.stopButtonModel);
    $(info).update("Activity stopped: " + this.activity);
    delete this.activity;
}

MainAssistant.prototype.activityStopFailure = function(event) {
    $(info).update("Error:<br>" + Object.toJSON(event));
}

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

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

MainAssistant.prototype.cleanup = function(event) {
    Mojo.Event.stopListening($(StartActivityButton), Mojo.Event.tap, this.onStartActivity);
    Mojo.Event.stopListening($(StopActivityButton), Mojo.Event.tap, this.onStopActivity);
    Mojo.Event.stopListening($(ExitButton), Mojo.Event.tap, this.onExit);
    this.onStopActivity();
}

На этом все.

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

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

Leave a Reply

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

О.

Обмен данными между сценами приложения для Palm WebOS с помощью Cookies

Очень часто в приложении необходимо передать данные, введенные пользователем, из одной формы в другую. В Palm WebOS для этих целей можно использовать Cookies. API для использования Cookies довольно прозрачно, как и многие другие вещи в WebOS, не требует особых умений.

В этот раз мы рассмотрим пример того, как различные сцены могут обмениваться данными.

Для начала создадим новое приложение, в нем новую сцену с названием Main и еще одну с названием Second. Как создать проект и сцену можно узнать из этой статьи.

Напишем HTML-шаблоны сцен:

views/main/main-scene.html

<div id="main" class="palm-hasheader">
<div class="palm-header">Main</div>
<div id="SecondSceneButton" x-mojo-element="Button"></div>
<div id="ExitButton" x-mojo-element="Button"></div>
<div id="counter" class="palm-body-text"></div>
</div>

views/second/second-scene.html

<div id="main" class="palm-hasheader">
     <div class="palm-header">Second Scene</div>
     <div id="CloseButton" x-mojo-element="Button"></div>
     <div id="valuetext" class="palm-body-text">Unknown value</div>
</div>

Главная сцена состоит из контейнера с заголовком, двух кнопок и текстового поля.
Вторая сцена состоит из контейнера с заголовком, кнопки и текстового поля.
Ничего сверхъестественного. 🙂

Перед тем, как написать логику, стоит ознакомиться со схемой, описывающей жизненный цикл сцены:

WebOS Scene Lifecycle

Из схемы можно узнать, что первым делом вызывается конструктор сцены, затем метод setup(), а когда сцена загрузилась, вызывается метод activate(). Также activate() вызывается при каждом появлении сцены на экране.

Что это нам даст? Посмотрим на пример кода ниже:

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

  Mojo.Event.listen(this.controller.get("SecondSceneButton"),
    Mojo.Event.tap,
    this.handleSecondSceneButton.bind(this));
  Mojo.Event.listen(this.controller.get("ExitButton"),
    Mojo.Event.tap,
    this.handleExitButton.bind(this));

  this.counter = 0;
  this.counterCookie = new Mojo.Model.Cookie("counterCookie");
  this.counterCookie.put(this.counter);
}

MainAssistant.prototype.activate = function(event) {
  this.counter = this.counterCookie.get();
  this.controller.get("counter").update(this.counter);
}

MainAssistant.prototype.cleanup = function(event) {
  this.counterCookie.remove();
}

В методе setup() мы создали переменную counter, поместили ее в Cookie с названием counterCookie, а в методе activate() мы берем значение из Cookie и отображаем в текстовом поле. И каждый раз, когда форма будет активизироваться, в текстовом поле будет появляться актуальное значение из Cookie.
Метод cleanup() вызывается в конце жизненного цикла сцены и в нем мы удаляем созданную Cookie.

Теперь напишем обработчик нажатия кнопки SecondSceneButton:

MainAssistant.prototype.handleSecondSceneButton = function(event) {
  this.counter++;
  this.counterCookie.put(this.counter);
  this.controller.stageController.pushScene("second", 1);
}

В обработчике мы прибавляем единицу к переменной counter, записываем ее значение в Cookie и отображаем сцену Second.

Дальше нам необходимо получить значение в сцене Second и как-то там поиспользовать.

function SecondAssistant() {
}

SecondAssistant.prototype.setup = function() {
  this.controller.setupWidget("CloseButton",
    {}, {label:"Close"});

  Mojo.Event.listen(this.controller.get("CloseButton"),
    Mojo.Event.tap,
    this.handleCloseButton.bind(this));
  this.counterCookie = new Mojo.Model.Cookie("counterCookie");
  this.controller.get("valuetext").update(this.counterCookie.get());
}

SecondAssistant.prototype.handleCloseButton = function(event) {
  var value = this.counterCookie.get();
  value++;
  this.counterCookie.put(value);
  this.controller.stageController.popScene();
}

В методе setup() сцены мы создаем объект Cookie, получаем сохраненное значение и отображаем его в текстовом поле.

В обработчике нажатия кнопки мы берем значение Cookie, прибавляем к нему единицу и записываем обратно в Cookie. Затем закрываем сцену.

После закрытия сцены Second будет отображена главная сцена Main и при активации вызовется метод activate(), в котором измененное значение снова появится в текстовом поле.

После всего наше приложение будет выглядеть так:

WebOS Cookies Test GUI

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