Pull to refresh

Пошаговое описание создания простого приложения для Samsung Bada

Reading time8 min
Views9.4K

Предварительные замечания


Здравствуйте. Хотелось бы прежде всего поздравить всех с наступившим Новым Годом и сразу перейти к делу. Эта статья будет посвящена вопросу создания простых программ для Bada — операционной системы для мобильных устройств, которые выпускает корейская Samsung. Заранее хочу сказать, что под катом простой рецепт изготовления простого приложения без пространных рассуждений о оптимальности и стройности кода.
На Хабре уже есть довольно обстоятельные статьи, которые посвящены Bada, например эта и эта, но вот пошагового описания создания приложения для новичков нет. Кому интересно — прошу под кат.


Тема для написания возникла случайно — знакомый активно занимается установлением границ земельных участков при помощи GPS в геодезической фирме; специфика работы (откуда взялась — хороший вопрос) состоит в том, что получаемые геодезические координаты (позволю себе пояснить, что имеется ввиду широта и долгота) надо переводить в прямоугольные прямо после их получения. На фирме ноутбуков, способных выдержать 8 часовой рабочий день нет и не планируется, зато знакомый недавно купил себе активно продвигаемый в Украине смартфон от Samsung с операционной системой Bada, далее последовал вопрос — если можно скачать игры для телефона, то нет ли приложения, способного решить описанную чисто инженерную задачу? Такого приложения, конечно, не нашлось, и я получил любезное предложение такое написать за известную плату.

Инструментарий

Для разработки приложений для Bada используется Bada SDK 1.2.0, скачать который можно, зарегистрировавшись на сайте для разработчиков Bada. В этом процессе нет ничего сложного, но вот на этапе выбора файлов для загрузки я, честно сказать, «протупил», скачав только SDK, а так называемый языковой пакет (language pack) нет, понадеявшись, что, как написано на сайте, его загрузка произойдет после установки SDK автоматически. Однако, на этапе установки что-то шло не так, установка продолжалась без загрузки языкового пакета, что в дальнейшем приводило к невозможности ни выполнить построение (build), ни, тем более, запустить приложение.
Загрузив SDK и языковой пакет, их следует положить в одном месте, и при установке SDK или при её модификации, установщик подхватит языковой пакет и выполнит инсталляцию его самостоятельно.

Собственно создание приложения


Среда разработки основана на Eclipse, используемый язык программирования С++. Начнем с того, что перейдем к созданию нового приложения очевидной командой File -> New -> bada Application Project. В появившемся окне следует определить название проекта в поле Project name, в списке Project Type выбрать тип приложения — bada Form Based Application.

Далее среда попросит определить технические параметры устройства, для которого будет предназначено приложение (разрешение экрана, наличие GPS и т.д.). Эти параметры определяются в специальном файле манифеста Manifest.xml, который можно выбрать среди файлов SDK, создать и загрузить с сайта Bada Developers или создать свой. Не мудрствуя лукаво, я использовал файл манифеста из папок с примерами Samples, которые устанавливаются вместе с SDK, поскольку мое приложение не требовало наличия «наворотов», а было важно только разрешение экрана.

Далее среда попросит указать корневую директорию SDK, с этим проблем возникнуть не должно. После выбора в списке появится название модели устройства и его API, которое будет использоваться в дальнейшем для программирования.

Следующий шаг — определение имени формы по умолчанию, которая появится сразу после запуска приложения. По этому имени будут сгенерированы *.h и *.cpp файлы.

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

Следующее звено в длинной цепочке настроек — определение Application ID, для удостоверения функций приложения, если ему требуется выполнять чтение и запись в защищенные папки. Мне это не требовалось, поэтому я этот шаг опустил.

Почти конец — определение очевидных свойств приложения Name, Vendor и Description.

И вот уже почти почти конец — это определение необходимых конфигураций для разработки: рекомендую оставить все по умолчанию, а сейчас наиболее важной конфигурацией является Simulator-Debug — это возможность отладки кода на симуляторе устройства, Target-Release — конфигурация для компилирования приложения пред выгрузкой его на реальное устройство.

Последний шаг — сведенная по всем настройкам информация в окне Итогов (Summary), которую можно еще раз прочитать и убедиться, что все выбрано правильно.

После финала настроек будущее приложение появляется в Project Explorer, щелчок по которому приводит к раскрытию файлов ресурсов в окне Resources и появлению следующего окна:

image

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

Я сразу перенес уже готовую кнопку, которую любезно сгенерировала среда, пониже и написал на ней Calculate. Располагая GUI Editor легко получить следующий интерфейс, который хорошо подходит для моей задачи (полагаю, что процесс переноса элементов управления на форму и установки их свойств никаких затруднений не вызывает); в качестве подписей к полям ввода использован очевидный Label, в качестве полей ввода — EditField; для показа результата вычислений также использованы Label, поскольку их редактирование не предусмотрено:

image

Теперь собственно кодирование.

Выполняющееся приложение проходит несколько этапов (Помощь очень подробная, там можно узнать детали), сейчас в первую очередь нас интересует этап иницализации приложения, за который отвечает метод OnInitializing(void) класса формы, который можно найти в файле <ВАША_ФОРМА>.cpp в папке src проекта.

По умолчанию этот метод выглядит следующим образом:

result
Form1::OnInitializing(void)
{
	result r = E_SUCCESS;

	// TODO: Add your initialization code here

	// Get a button via resource ID
	__pButtonOk = static_cast<Button *>(GetControl(L"IDC_BUTTON_OK"));
	if (__pButtonOk != null)
	{
		__pButtonOk->SetActionId(ID_BUTTON_OK);
		__pButtonOk->AddActionEventListener(*this);
	}

	return r;
}

Здесь создана кнопка с идентификатором __pButtonOk, которая была сгенерирована средой. В папке inc находится заголовочный файл формы, в котором в секцию protected следует добавить новое поле, которое будет соответствовать второй кнопке Clear, а также идентификатор события (Id Action) кнопки в виде целочисленной константы, который будет предназначен для определения того, какая кнопка формы была нажата в методе OnActionPerformed. Также я сюда добавил специальные константы, нужные для вычислений.

Я сделал это так:
protected:
	static const int ID_BUTTON_OK = 101;
	// new action ID for button CLEAR
	static const int ID_BUTTON_CLEAR=102;
	// geodetic constants
	static const int a=6378137;
	static const float alfa=1/298.257223563;
	Osp::Ui::Controls::Button *__pButtonOk;
	// new field: button
	Osp::Ui::Controls::Button *__pButtonClear;
	// new fields: edits and labels
	Osp::Ui::Controls::EditField *__pB_deg;
	Osp::Ui::Controls::EditField *__pB_min;
	Osp::Ui::Controls::EditField *__pB_sec;
	Osp::Ui::Controls::EditField *__pL_deg;
	Osp::Ui::Controls::EditField *__pL_min;
	Osp::Ui::Controls::EditField *__pL_sec;
	Osp::Ui::Controls::EditField *__pH;
	Osp::Ui::Controls::Label *__pX;
	Osp::Ui::Controls::Label *__pY;


Теперь в методе OnInitializing(void) можно создать кнопку Clear и назначить ей Id Action и «слушатель» Event Listener. Аналогично поступим и с EditField и с Label, не добавляя к ним, однако, Id Action и Event Listener поскольку их реакция на действия пользователя в нашем простом приложении не предусмотрена (IDC_BUTTON1, IDC_EDITFIELD1 и т.д. — значения свойства Name для кнопки).

	__pButtonOk = static_cast<Button *>(GetControl(L"IDC_BUTTON_OK"));
	__pButtonClear = static_cast<Button *>(GetControl(L"IDC_BUTTON1"));
	
	if (__pButtonOk != null)
		{
			__pButtonOk->SetActionId(ID_BUTTON_OK);
			__pButtonOk->AddActionEventListener(*this);
		}
		if (__pButtonClear != null)
			{
				__pButtonClear->SetActionId(ID_BUTTON_CLEAR);
				__pButtonClear->AddActionEventListener(*this);
			}
	// Get fields and labels
	__pB_deg = static_cast<EditFields *>(GetControl(L"IDC_EDITFIELD1"));
	__pB_min = static_cast<EditFields *>(GetControl(L"IDC_EDITFIELD2"));
	__pB_sec = static_cast<EditFields *>(GetControl(L"IDC_EDITFIELD3"));

	__pL_deg = static_cast<EditFields *>(GetControl(L"IDC_EDITFIELD4"));
	__pL_min = static_cast<EditFields *>(GetControl(L"IDC_EDITFIELD5"));
	__pL_sec = static_cast<EditFields *>(GetControl(L"IDC_EDITFIELD6"));
       __pH = static_cast<EditField *>(GetControl(L"IDC_EDITFIELD7"));


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

Чтобы решить эту задачу, используется метод класса формы OnActionPerformed(const Osp::Ui::Control& source, int actionId). Как видно, вторым параметром является уже упоминаемый выше Action Id. При выполнении приложения «прослушиваются» события нажатия кнопок и назначенный им Action Id передается в OnActionPerformed(const Osp::Ui::Control& source, int actionId). Если здесь предусмотрена обработка для такого идентификатора, она и выполняется.

В OnActionPerformed есть заготовка switch для анализа параметра actionId, её удобно использовать. Далее я позволю себе привести код этого метода с подробными комментариями:

void
Form1::OnActionPerformed(const Osp::Ui::Control& source, int actionId)
{
	const int MAX_BUFF_SIZE = 512;	
	switch(actionId)
	{
	case ID_BUTTON_OK:
    // реакция на нажатие кнопки Calculate		
		{
	// получаем строковое представление градусов, минут и секунд широты и ...
			String B_deg_str(__pB_deg->GetText());
			String B_min_str(__pB_min->GetText());
			String B_sec_str(__pB_sec->GetText());
    //...долготы
			String L_deg_str(__pL_deg->GetText());
			String L_min_str(__pL_min->GetText());
			String L_sec_str(__pL_sec->GetText());
    // ... высоты
			String H_str(__pH->GetText());

            double B_deg,B_min,B_sec;
            double L_deg,L_min,L_sec;
            double H;
    // преобразование строковых представлений чисел в вещественную форму для вычислений
            result r1=Double::Parse(B_deg_str,B_deg);
            result r2=Double::Parse(B_min_str,B_min);
            result r3=Double::Parse(B_sec_str,B_sec);

            result r4=Double::Parse(L_deg_str,L_deg);
            result r5=Double::Parse(L_min_str,L_min);
            result r6=Double::Parse(L_sec_str,L_sec);

            result r7=Double::Parse(H_str,H);
    // вычисления
            double b_in_decimal=B_deg+B_min/60+B_sec/3600;
            double l_in_decimal=L_deg+L_min/60+L_sec/3600;

            double eSqr=2*alfa-(alfa*alfa);
            double N=a/Math::Sqrt(1-eSqr*(Math::Sin(b_in_decimal))*(Math::Sin(b_in_decimal)));

            double X=(N+H)*Math::Cos(b_in_decimal)*Math::Cos(l_in_decimal);
            double Y=(N+H)*Math::Cos(b_in_decimal)*Math::Sin(l_in_decimal);

            String strX;
            String strY;
     // преобразование числовых значений координат в строковое представление 
            strX.Format(MAX_BUFF_SIZE,L"%f",X);
            strY.Format(MAX_BUFF_SIZE,L"%f",Y);
    // вывод полученых чисел в Label   
            __pX->SetText(L"X="+strX);__pY->SetText(L"Y="+strY);
            __pX->Draw();__pY->Draw();
            __pX->Show();__pY->Show();

		}
		break;
	case ID_BUTTON_CLEAR:
	{
		// реакция на нажатие кнопки Clear
		// создаем диалоговое окно с кнопками  OK и CANCEL и вопросом - очистить все поля?   
		         MessageBox *pMessageBox = new MessageBox();
		         pMessageBox->Construct(L"MessageBox", L"Clear all fields?" , MSGBOX_STYLE_OKCANCEL ,9000);
		         int ModalResult;
		         pMessageBox->ShowAndWait(ModalResult);
	    // если ответ положительный,то ...	         
		         if (ModalResult==MSGBOX_RESULT_OK) {
		// ... очищаем поля ввода и надписи Label        	 
		        	 __pB_deg->Clear();
		        	 __pB_min->Clear();
		        	 __pB_sec->Clear();
		        	 __pL_deg->Clear();
		        	 __pL_min->Clear();
		        	 __pL_sec->Clear();
		        	 __pH->Clear();
		        	 __pX->SetText(L"X=");__pY->SetText(L"Y=");
		         }
		// удаляем MessageBox         
		         delete pMessageBox;
	}
		break;
	default:
		break;
	}
}


Внешний вид симулятора с запущенной программой выглядит следующим образом:

image

Он же с MessageBox:

image

Вот, кажется, и все. Хочу отметить, что приложение нисколько не претендует на широту охвата и корректность всех формулировок, например, напрочь отсутствует «защита от дурака», поскольку я надеюсь на вменяемость моего знакомого и четверых его коллег, для которых эта программа предназначена.
Совсем недавно поступила ещё одна заявка на разработку для Bada — необходим поиск и отображение на карте ближайших объектов, вроде банкоматов или терминалов пополнения счета. Если эта тема кому-нибудь будет интересна, я с удовольствием поделюсь опытом.

Если у кого-либо возник вопрос, что, собственно, с программой делать дальше, то это подробно освещено в статьях на сайте Bada Developer, я этого касаться не буду, поскольку программирование все-таки тема посложнее.

Исходники приложения доступны здесь.

Если что-то не так я сделал с хостингом, извините, пожалуйста:)

UPD: Простите, забыл добавить — все добавленные поля класса формы (__pB_deg, _pB_min и т.д.) следует инициализировать в конструкторе формы так:

Form1::Form1(void):
		__pB_deg(null),__pB_min(null),__pB_sec(null),
	        __pL_deg(null),__pL_min(null),__pL_sec(null),
	        __pH(null),
                 __pX(null),__pY(null)
{
}
Tags:
Hubs:
+38
Comments21

Articles