Pada artikel ini akan dijelaskan bagaimana membuat aplikasi sederhana yang memanfaatkan Accessory SDK. Untuk mengikuti tutorial ini dibutuhkan sebuah Smart Device (Samsung Galaxy) dan sebuah Accessory Device (Samsung Gear).
Apa itu Accessory SDK?
Samsung SDK memungkinkan untuk kamu bisa membuat aplikasi yang saling terintegrasi antara Smart Device dengan Accessory Device. Ada beberapa macam Accessory Device, antara lain adalah Health Care Device, Gaming Console, Printing Device, Smart TV, dll. Dengan Accessory SDK ini kamu bisa membuat aplikasi yang mengintegrasikan kedua device misalnya seperti mengendalikan ponsel kamu dengan smart watch.
💻 Mulai Belajar Pemrograman
Belajar pemrograman di Dicoding Academy dan mulai perjalanan Anda sebagai developer profesional.
Daftar SekarangFitur apa saja yang bisa dimanfaatkan dari Accessory SDK?
Ada banyak yang bisa kamu manfaatkan dari Accessory SDK ini seperti mengontrol Smart Device secara remote, transfer file dengan ukuran yang tak terbatas, melihat notifikasi yang masuk ke ponsel pada smart watch, dll. Namun ada beberapa batasan dari SDK ini, SDK ini hanya mendukung tipe Galaxy Gear, Gear 2, Gear 2 Neo, Gear S, Gear S2, dan Gear S3. Selain itu setiap perangkat harus sudah terinstall Samsung Accessory Service Framework terlebih dahulu. Dan untuk Smart Device, hanya perangkat yang menggunakan OS Android 4.3 keatas.
Mungkin cukup segitu penjelasan singkat seputar Accessory SDK, untuk lebih lengkapnya bisa ikuti akademi Samsung Galaxy SDK.
Latihan
Pada latihan ini kita akan mencoba membuat aplikasi yang memanfaatkan Accessory SDK. Aplikasi sederhana yang akan kita buat adalah aplikasi untuk menderingkan Smart Device dari Accessory Device. Aplikasi ini bisa berguna jika suatu saat kamu lupa menaruh ponsel kamu, maka kamu tinggal menggunakan aplikasi pada smart watch yang kamu pakai untuk mencari ponsel kamu. Tutorial ini akan menghasilkan 2 aplikasi. Aplikasi pertama adalah aplikasi consumer yang akan berjalan pada smart watch (Samsung Gear). Sedangkan aplikasi kedua adalah aplikasi provider yang akan berjalan pada ponsel kamu (Samsung Galaxy). Langsung saja ikuti step by step berikut.
Aplikasi Consumer
Aplikasi ini akan dibuat menggunakan Tizen Studio dengan bahasa pemrograman C.
- Buka Tizen Studio dan buat project baru bernama FindPhone.
- Pada buat folder inc terdapat class findphone.h kondisikan kodenya sesuai dengan kode berikut.
123456789101112131415161718192021222324#ifndef __FIND_PHONE_H__#define __FIND_PHONE_H__#include <app.h>#include <glib.h>#include <Elementary.h>#include <system_settings.h>#include <efl_extension.h>#include <dlog.h>#define TAG "FindPhone"void initialize_sap();gboolean find_peers();gboolean request_service_connection(void);gboolean terminate_service_connection(void);gboolean send_data(char *message);void update_ui(char *data);#if !defined(PACKAGE)#define PACKAGE "com.dicoding.findphone"#endif#endif - Pada folder res, buat folder baru dengan nama xml dan tambahkan class baru didalamnya dengan nama accessorryservice.xml dan tambahkan kode berikut.
123456789101112131415<?xml version="1.0" encoding="UTF-8"?><resources><application name="com.dicoding.findphone"><serviceProfile id="/sample/hello" name="FindPhone"role="consumer" version="1.0"><supportedTransports><transport type="TRANSPORT_BT" /><transport type="TRANSPORT_WIFI" /></supportedTransports><serviceChannel id="104" dataRate="low" priority="low"reliability="enable"></serviceChannel></serviceProfile></application></resources> - Pada folder src, buat class baru dengan nama sap.c dan tambahkan kode berikut. Class ini berisi kumpulan function yang akan digunakan untuk mengubungkan Accessory Device dengan Smart Device.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366#include <findphone.h>#include <glib.h>#include <sap.h>#define FIND_PHONE_PROFILE_ID "/sample/hello"#define FIND_PHONE_CHANNELID 104struct priv {sap_agent_h agent;sap_socket_h socket;sap_peer_agent_h peer_agent;};static gboolean agent_created = FALSE;static struct priv priv_data = { 0 };void on_peer_agent_updated(sap_peer_agent_h peer_agent,sap_peer_agent_status_e peer_status,sap_peer_agent_found_result_e result,void *user_data){switch (result) {case SAP_PEER_AGENT_FOUND_RESULT_DEVICE_NOT_CONNECTED:dlog_print(DLOG_INFO, TAG, "device is not connected");break;case SAP_PEER_AGENT_FOUND_RESULT_FOUND:if (peer_status == SAP_PEER_AGENT_STATUS_AVAILABLE) {priv_data.peer_agent = peer_agent;dlog_print(DLOG_INFO, TAG, "Find Peer Success!!");request_service_connection();} else {dlog_print(DLOG_INFO, TAG, "peer agent removed");sap_peer_agent_destroy(peer_agent);}break;case SAP_PEER_AGENT_FOUND_RESULT_SERVICE_NOT_FOUND:dlog_print(DLOG_INFO, TAG, "service not found");break;case SAP_PEER_AGENT_FOUND_RESULT_TIMEDOUT:dlog_print(DLOG_INFO, TAG, "peer agent find timed out");break;case SAP_PEER_AGENT_FOUND_RESULT_INTERNAL_ERROR:dlog_print(DLOG_INFO, TAG, "peer agent find search failed");break;}}static void on_service_connection_terminated(sap_peer_agent_h peer_agent,sap_socket_h socket,sap_service_connection_terminated_reason_e result,void *user_data){switch (result) {case SAP_CONNECTION_TERMINATED_REASON_PEER_DISCONNECTED:dlog_print(DLOG_INFO, TAG, "disconnected because peer lost");update_ui("Peer Disconnected");break;case SAP_CONNECTION_TERMINATED_REASON_DEVICE_DETACHED:dlog_print(DLOG_INFO, TAG, "disconnected because device is detached");update_ui("Disconnected Device Detached");break;case SAP_CONNECTION_TERMINATED_REASON_UNKNOWN:dlog_print(DLOG_INFO, TAG, "disconnected because of unknown reason");update_ui("Disconnected Unknown Reason");break;}sap_socket_destroy(priv_data.socket);priv_data.socket = NULL;dlog_print(DLOG_INFO, TAG, "status:%d", result);}static void on_data_recieved(sap_socket_h socket,unsigned short int channel_id,unsigned int payload_length,void *buffer,void *user_data){dlog_print(DLOG_INFO, TAG, "received data: %s, len:%d", buffer, payload_length);update_ui(buffer);}static void on_service_connection_created(sap_peer_agent_h peer_agent,sap_socket_h socket,sap_service_connection_result_e result,void *user_data){switch (result) {case SAP_CONNECTION_SUCCESS:dlog_print(DLOG_INFO, TAG, "peer agent connection is successful, pa :%u", peer_agent);sap_peer_agent_set_service_connection_terminated_cb(priv_data.peer_agent,on_service_connection_terminated,NULL);sap_socket_set_data_received_cb(socket, on_data_recieved, peer_agent);priv_data.socket = socket;update_ui("Connection Established");break;case SAP_CONNECTION_ALREADY_EXIST:dlog_print(DLOG_INFO, TAG, "connection is already exist");priv_data.socket = socket;update_ui("Connection already exist");break;case SAP_CONNECTION_FAILURE_DEVICE_UNREACHABLE:dlog_print(DLOG_INFO, TAG, "device is not unreachable");update_ui("Device Not Reachable");break;case SAP_CONNECTION_FAILURE_INVALID_PEERAGENT:dlog_print(DLOG_INFO, TAG, "invalid peer agent");update_ui("Invalid Peer Agent");break;case SAP_CONNECTION_FAILURE_NETWORK:dlog_print(DLOG_INFO, TAG, "network failure");update_ui("Network Failure");break;case SAP_CONNECTION_FAILURE_PEERAGENT_NO_RESPONSE:dlog_print(DLOG_INFO, TAG, "peer agent is no response");update_ui("PEERAGENT_NO_RESPONSE");break;case SAP_CONNECTION_FAILURE_PEERAGENT_REJECTED:dlog_print(DLOG_INFO, TAG, "peer agent is rejected");update_ui("PEERAGENT_REJECTED");break;case SAP_CONNECTION_FAILURE_UNKNOWN:dlog_print(DLOG_INFO, TAG, "unknown error");update_ui("UNKNOWN_ERROR");break;}}static gboolean _create_service_connection(gpointer user_data){struct priv *priv = NULL;sap_result_e result = SAP_RESULT_FAILURE;priv = (struct priv *)user_data;result = sap_agent_request_service_connection(priv->agent,priv->peer_agent,on_service_connection_created,NULL);if (result == SAP_RESULT_SUCCESS) {dlog_print(DLOG_DEBUG, TAG, "req service conn call succeeded");} else {update_ui("Connection Establishment Failed");dlog_print(DLOG_ERROR, TAG, "req service conn call is failed (%d)", result);}return FALSE;}gboolean request_service_connection(void){g_idle_add(_create_service_connection, &priv_data);dlog_print(DLOG_DEBUG, TAG, "request_service_connection call over");return TRUE;}static gboolean _terminate_service_connection(gpointer user_data){struct priv *priv = NULL;sap_result_e result = SAP_RESULT_FAILURE;priv = (struct priv *)user_data;if (priv->socket)result = sap_peer_agent_terminate_service_connection(priv->peer_agent);else {update_ui("No service Connection");return FALSE;}if (result == SAP_RESULT_SUCCESS) {update_ui("Connection Terminated");dlog_print(DLOG_DEBUG, TAG, "req service conn call succeeded");} else {update_ui("Connection Termination Failed");dlog_print(DLOG_ERROR, TAG, "req service conn call is failed (%d)", result);}return FALSE;}gboolean terminate_service_connection(void){g_idle_add(_terminate_service_connection, &priv_data);return TRUE;}static gboolean _find_peer_agent(gpointer user_data){struct priv *priv = NULL;sap_result_e result = SAP_RESULT_FAILURE;priv = (struct priv *)user_data;result = sap_agent_find_peer_agent(priv->agent, on_peer_agent_updated, NULL);if (result == SAP_RESULT_SUCCESS) {dlog_print(DLOG_DEBUG, TAG, "find peer call succeeded");} else {dlog_print(DLOG_ERROR, TAG, "findsap_peer_agent_s is failed (%d)", result);}dlog_print(DLOG_DEBUG, TAG, "find peer call is over");return FALSE;}gboolean find_peers(){g_idle_add(_find_peer_agent, &priv_data);dlog_print(DLOG_DEBUG, TAG, "find peer called");return TRUE;}gboolean send_data(char *message){int result;if (priv_data.socket) {dlog_print(DLOG_INFO, TAG, "Sending data ");result = sap_socket_send_data(priv_data.socket, FIND_PHONE_CHANNELID, strlen(message), message);} else {update_ui("No service Connection");return FALSE;}return TRUE;}static void on_agent_initialized(sap_agent_h agent,sap_agent_initialized_result_e result,void *user_data){switch (result) {case SAP_AGENT_INITIALIZED_RESULT_SUCCESS:dlog_print(DLOG_INFO, TAG, "agent is initialized");priv_data.agent = agent;agent_created = TRUE;break;case SAP_AGENT_INITIALIZED_RESULT_DUPLICATED:dlog_print(DLOG_INFO, TAG, "duplicate registration");break;case SAP_AGENT_INITIALIZED_RESULT_INVALID_ARGUMENTS:dlog_print(DLOG_INFO, TAG, "invalid arguments");break;case SAP_AGENT_INITIALIZED_RESULT_INTERNAL_ERROR:dlog_print(DLOG_INFO, TAG, "internal sap error");break;default:dlog_print(DLOG_INFO, TAG, "unknown status (%d)", result);break;}dlog_print(DLOG_INFO, TAG, "agent initialized callback is over");}static void on_device_status_changed(sap_device_status_e status, sap_transport_type_e transport_type,void *user_data){switch (transport_type) {case SAP_TRANSPORT_TYPE_BT:dlog_print(DLOG_INFO, TAG, "connectivity type(%d): bt", transport_type);break;case SAP_TRANSPORT_TYPE_BLE:dlog_print(DLOG_INFO, TAG, "connectivity type(%d): ble", transport_type);break;case SAP_TRANSPORT_TYPE_TCP:dlog_print(DLOG_INFO, TAG, "connectivity type(%d): tcp/ip", transport_type);break;case SAP_TRANSPORT_TYPE_USB:dlog_print(DLOG_INFO, TAG, "connectivity type(%d): usb", transport_type);break;case SAP_TRANSPORT_TYPE_MOBILE:dlog_print(DLOG_INFO, TAG, "connectivity type(%d): mobile", transport_type);break;default:dlog_print(DLOG_INFO, TAG, "unknown connectivity type (%d)", transport_type);break;}switch (status) {case SAP_DEVICE_STATUS_DETACHED:if (priv_data.peer_agent) {sap_socket_destroy(priv_data.socket);priv_data.socket = NULL;sap_peer_agent_destroy(priv_data.peer_agent);priv_data.peer_agent = NULL;}break;case SAP_DEVICE_STATUS_ATTACHED:if (agent_created) {g_idle_add(_find_peer_agent, &priv_data);}break;default:dlog_print(DLOG_INFO, TAG, "unknown status (%d)", status);break;}}gboolean agent_initialize(){int result = 0;do {result = sap_agent_initialize(priv_data.agent, FIND_PHONE_PROFILE_ID, SAP_AGENT_ROLE_CONSUMER,on_agent_initialized, NULL);dlog_print(DLOG_DEBUG, TAG, "SAP >>> getRegisteredServiceAgent() >>> %d", result);} while (result != SAP_RESULT_SUCCESS);return TRUE;}void initialize_sap(){sap_agent_h agent = NULL;sap_agent_create(&agent);if (agent == NULL)dlog_print(DLOG_INFO, TAG, "ERROR in creating agent");elsedlog_print(DLOG_ERROR, TAG, "SUCCESSFULLY create sap agent");priv_data.agent = agent;sap_set_device_status_changed_cb(on_device_status_changed, NULL);agent_initialize();} - Terakhir buka class findphone.c, pada class ini kita akan membuat UI sederhana dan menambahkan action untuk bisa membunyikan ringtone pada Smart Device. Tambahkan kondisikan kodenya menjadi seperti berikut.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347#include <findphone.h>typedef struct appdata {Evas_Object *win;Evas_Object *naviframe;Evas_Object *rect[10];Eext_Circle_Surface *circle_surface;Evas_Object *circle_genlist;} appdata_s;static appdata_s *object;static void win_delete_request_cb(void *data, Evas_Object *obj, void *event_info){ui_app_exit();}static void _timeout_cb(void *data, Evas_Object *obj, void *event_info){if (!obj) return;elm_popup_dismiss(obj);}static void _block_clicked_cb(void *data, Evas_Object *obj, void *event_info){if (!obj) return;elm_popup_dismiss(obj);}static void _popup_hide_cb(void *data, Evas_Object *obj, void *event_info){if (!obj) return;elm_popup_dismiss(obj);}static void _popup_hide_finished_cb(void *data, Evas_Object *obj, void *event_info){if (!obj) return;evas_object_del(obj);}static void _popup_toast_cb(Evas_Object *parent, char *string){Evas_Object *popup;popup = elm_popup_add(parent);elm_object_style_set(popup, "toast/circle");elm_popup_orient_set(popup, ELM_POPUP_ORIENT_BOTTOM);evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);eext_object_event_callback_add(popup, EEXT_CALLBACK_BACK, _popup_hide_cb, NULL);evas_object_smart_callback_add(popup, "dismissed", _popup_hide_finished_cb, NULL);elm_object_part_text_set(popup, "elm.text", string);evas_object_smart_callback_add(popup, "block,clicked", _block_clicked_cb, NULL);elm_popup_timeout_set(popup, 2.0);evas_object_smart_callback_add(popup, "timeout", _timeout_cb, NULL);evas_object_show(popup);}void update_ui(char *data){dlog_print(DLOG_INFO, TAG, "Updating UI with data %s", data);_popup_toast_cb(object->naviframe, data);}static void btn_cb_connect(void *data, Evas_Object *obj, void *event_info){Elm_Object_Item *it = event_info;elm_genlist_item_selected_set(it, EINA_FALSE);dlog_print(DLOG_DEBUG, TAG, "AGENT_INITIALISED");find_peers();}static void btn_cb_send(void *data, Evas_Object *obj, void *event_info){Elm_Object_Item *it = event_info;elm_genlist_item_selected_set(it, EINA_FALSE);send_data("Find My Phone!");}static void btn_cb_disconnect(void *data, Evas_Object *obj, void *event_info){Elm_Object_Item *it = event_info;elm_genlist_item_selected_set(it, EINA_FALSE);terminate_service_connection();}char *main_menu_names[] = {"Connect", "Find My Phone", "Disconnect",NULL};typedef struct _item_data {int index;Elm_Object_Item *item;} item_data;static char *_gl_title_text_get(void *data, Evas_Object *obj, const char *part){char buf[1024];snprintf(buf, 1023, "%s", "FindPhone");return strdup(buf);}static char *_gl_sub_title_text_get(void *data, Evas_Object *obj, const char *part){char buf[1024];snprintf(buf, 1023, "%s", "Consumer");return strdup(buf);}static char *_gl_main_text_get(void *data, Evas_Object *obj, const char *part){char buf[1024];item_data *id = data;int index = id->index;if (!strcmp(part, "elm.text"))snprintf(buf, 1023, "%s", main_menu_names[index - 1]);return strdup(buf);}static void _gl_del(void *data, Evas_Object *obj){// FIXME: Unrealized callback can be called after this.// Accessing Item_Data can be dangerous on unrealized callback.item_data *id = data;if (id) free(id);}static Eina_Bool _naviframe_pop_cb(void *data, Elm_Object_Item *it){ui_app_exit();return EINA_FALSE;}static void create_list_view(appdata_s *ad){Evas_Object *genlist = NULL;Evas_Object *naviframe = ad->naviframe;Elm_Object_Item *nf_it = NULL;item_data *id = NULL;int index = 0;Elm_Genlist_Item_Class *itc = elm_genlist_item_class_new();Elm_Genlist_Item_Class *titc = elm_genlist_item_class_new();Elm_Genlist_Item_Class *pitc = elm_genlist_item_class_new();Elm_Genlist_Item_Class *gic = elm_genlist_item_class_new();/* Genlist Item Style */itc->item_style = "1text";itc->func.text_get = _gl_main_text_get;itc->func.del = _gl_del;/* Genlist Title Item Style */titc->item_style = "title";titc->func.text_get = _gl_title_text_get;titc->func.del = _gl_del;gic->item_style = "groupindex";gic->func.text_get = _gl_sub_title_text_get;gic->func.del = _gl_del;pitc->item_style = "padding";/* Create Genlist */genlist = elm_genlist_add(naviframe);elm_genlist_mode_set(genlist, ELM_LIST_COMPRESS);evas_object_smart_callback_add(genlist, "selected", NULL, NULL);/* Create Circle Genlist */ad->circle_genlist = eext_circle_object_genlist_add(genlist, ad->circle_surface);/* Set Scroller Policy */eext_circle_object_genlist_scroller_policy_set(ad->circle_genlist, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);/* Activate Rotary Event */eext_rotary_object_event_activated_set(ad->circle_genlist, EINA_TRUE);/* Title Item Here */id = calloc(sizeof(item_data), 1);elm_genlist_item_append(genlist, titc, NULL, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);id = calloc(sizeof(item_data), 1);id->index = index++;id->item = elm_genlist_item_append(genlist, gic, id, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);/* Main Menu Items Here*/id = calloc(sizeof(item_data), 1);id->index = index++;id->item = elm_genlist_item_append(genlist, itc, id, NULL, ELM_GENLIST_ITEM_NONE, btn_cb_connect, ad);id = calloc(sizeof(item_data), 1);id->index = index++;id->item = elm_genlist_item_append(genlist, itc, id, NULL, ELM_GENLIST_ITEM_NONE, btn_cb_send, ad);id = calloc(sizeof(item_data), 1);id->index = index++;id->item = elm_genlist_item_append(genlist, itc, id, NULL, ELM_GENLIST_ITEM_NONE, btn_cb_disconnect, ad);/* Padding Item Here */elm_genlist_item_append(genlist, pitc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, ad);nf_it = elm_naviframe_item_push(naviframe, NULL, NULL, NULL, genlist, "empty");elm_naviframe_item_pop_cb_set(nf_it, _naviframe_pop_cb, ad->win);}static void create_base_gui(appdata_s *ad){Evas_Object *conform = NULL;/* Window */ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);elm_win_autodel_set(ad->win, EINA_TRUE);evas_object_smart_callback_add(ad->win, "delete,request", win_delete_request_cb, NULL);/* Conformant */conform = elm_conformant_add(ad->win);evas_object_size_hint_weight_set(conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);elm_win_resize_object_add(ad->win, conform);evas_object_show(conform);/* Naviframe */ad->naviframe = elm_naviframe_add(conform);elm_object_content_set(conform, ad->naviframe);/* Eext Circle Surface*/ad->circle_surface = eext_circle_surface_naviframe_add(ad->naviframe);/* Main View */create_list_view(ad);eext_object_event_callback_add(ad->naviframe, EEXT_CALLBACK_BACK, eext_naviframe_back_cb, NULL);eext_object_event_callback_add(ad->naviframe, EEXT_CALLBACK_MORE, eext_naviframe_more_cb, NULL);/* Show window after base gui is set up */evas_object_show(ad->win);}static bool app_create(void *data){/* Hook to take necessary actions before main event loop startsInitialize UI resources and application's dataIf this function returns true, the main loop of application startsIf this function returns false, the application is terminated */object = data;create_base_gui(object);initialize_sap();return TRUE;}static void app_control(app_control_h app_control, void *data){/* Handle the launch request. */}static void app_pause(void *data){/* Take necessary actions when application becomes invisible. */}static void app_resume(void *data){/* Take necessary actions when application becomes visible. */}static void app_terminate(void *data){/* Release all resources. */}static void ui_app_lang_changed(app_event_info_h event_info, void *user_data){/*APP_EVENT_LANGUAGE_CHANGED*/char *locale = NULL;system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &locale);elm_language_set(locale);free(locale);return;}static void ui_app_orient_changed(app_event_info_h event_info, void *user_data){/*APP_EVENT_DEVICE_ORIENTATION_CHANGED*/return;}static void ui_app_region_changed(app_event_info_h event_info, void *user_data){/*APP_EVENT_REGION_FORMAT_CHANGED*/}static void ui_app_low_battery(app_event_info_h event_info, void *user_data){/*APP_EVENT_LOW_BATTERY*/}static void ui_app_low_memory(app_event_info_h event_info, void *user_data){/*APP_EVENT_LOW_MEMORY*/}int main(int argc, char *argv[]){appdata_s ad = { 0, };int ret = 0;ui_app_lifecycle_callback_s event_callback = { 0, };app_event_handler_h handlers[5] = { NULL, };event_callback.create = app_create;event_callback.terminate = app_terminate;event_callback.pause = app_pause;event_callback.resume = app_resume;event_callback.app_control = app_control;ui_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY, ui_app_low_battery, &ad);ui_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY, ui_app_low_memory, &ad);ui_app_add_event_handler(&handlers[APP_EVENT_DEVICE_ORIENTATION_CHANGED], APP_EVENT_DEVICE_ORIENTATION_CHANGED, ui_app_orient_changed, &ad);ui_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, ui_app_lang_changed, &ad);ui_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED, ui_app_region_changed, &ad);ui_app_remove_event_handler(handlers[APP_EVENT_LOW_MEMORY]);ret = ui_app_main(argc, argv, &event_callback, &ad);if (ret != APP_ERROR_NONE) {dlog_print(DLOG_ERROR, TAG, "ui_app_main() is failed. err = %d", ret);}return ret;} - Jalankan aplikasinya pada Samsung Gear kamu.
Aplikasi Provider
Aplikasi ini dibuat dengan Android Studio. Aplikasi tidak akan menampilkan UI ketika pertama dijalankan. Namun ketika kamu menderingkan ponsel dengan smart watch, ponsel akan berdering dan aplikasi akan menampilkan UI dengan text dan button untuk mematikan nada dering tersebut.
- Buka Android Studio dan buat project baru dengan nama FindPhone, kemudial pilih template Add no activity.
- Tambahkan library Accessory SDKyang bisa didownload di situs http://developer.samsung.com/galaxy/accessory.
- Buatlah res value baru dan beri nama accessoryservices, masukkan ke dalam res xml. Kondisikan codenya seperti berikut.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051<!DOCTYPE resources [<!ELEMENT resources (application)><!ELEMENT application (serviceProfile)+><!ATTLIST application name CDATA #REQUIRED><!ELEMENT serviceProfile (supportedTransports, serviceChannel+) ><!ATTLIST application xmlns:android CDATA #IMPLIED><!ATTLIST serviceProfile xmlns:android CDATA #IMPLIED><!ATTLIST serviceProfile serviceImpl CDATA #REQUIRED><!ATTLIST serviceProfile role (PROVIDER | CONSUMER | provider | consumer) #REQUIRED><!ATTLIST serviceProfile name CDATA #REQUIRED><!ATTLIST serviceProfile id CDATA #REQUIRED><!ATTLIST serviceProfile version CDATA #REQUIRED><!ATTLIST serviceProfile serviceLimit (ANY | ONE_ACCESSORY | ONE_PEERAGENT | any | one_accessory | one_peeragent) #IMPLIED><!ATTLIST serviceProfile serviceTimeout CDATA #IMPLIED><!ELEMENT supportedTransports (transport)+><!ATTLIST supportedTransports xmlns:android CDATA #IMPLIED><!ELEMENT transport EMPTY><!ATTLIST transport xmlns:android CDATA #IMPLIED><!ATTLIST transport type (TRANSPORT_WIFI | TRANSPORT_BT | TRANSPORT_BLE | TRANSPORT_USB |transport_wifi | transport_bt | transport_ble | transport_usb) #REQUIRED><!ELEMENT serviceChannel EMPTY><!ATTLIST serviceChannel xmlns:android CDATA #IMPLIED><!ATTLIST serviceChannel id CDATA #REQUIRED><!ATTLIST serviceChannel dataRate (LOW | HIGH | low | high) #REQUIRED><!ATTLIST serviceChannel priority (LOW | MEDIUM | HIGH | low | medium | high) #REQUIRED><!ATTLIST serviceChannel reliability (ENABLE | DISABLE | enable | disable ) #REQUIRED>]><resources><application name="FindPhoneProvider" ><serviceProfileid="/sample/hello"name="findphone"role="provider"serviceImpl="com.dicoding.findphone.ProviderService"version="1.0"serviceLimit="ANY"serviceTimeout="10"><supportedTransports><transport type="TRANSPORT_BT" /><transport type="TRANSPORT_WIFI" /></supportedTransports><serviceChannelid="104"dataRate="low"priority="low"reliability= "enable"/></serviceProfile></application></resources> - Buka string.xml dan tambahkan string value berikut ini.
1234567<string name="your_phone_has_been_rung_by_your_accessory_device">Your phone has been rung by your accessory device!</string><string name="ok">OK!</string><string name="ConnectionAcceptedMsg">Service Connection has been accepted.</string><string name="ConnectionEstablishedMsg">Service Connection has been established.</string><string name="ConnectionTerminateddMsg">Service Connection has been terminated.</string><string name="ConnectionAlreadyExist">Service Connection has already been existed!!!</string><string name="ConnectionAlreadyDisconnected">Service Connection has already been disconnected!!!</string> - Buat class baru dengan nama ProviderService.Java dan tambahkan kode berikut. Class ini digunakan untuk menerima permintaan koneksi dari Accessory Device. Pada class ini terdapat method onReceive yang berisi fungsi untuk melakukan action yaitu menderingkan ponsel dan membuka activity untuk mematikan ringtone yang berbunyi.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148public class ProviderService extends SAAgent {private static final String TAG = "FindMyPhone";private static final Class<ServiceConnection> SASOCKET_CLASS = ServiceConnection.class;private final IBinder mBinder = new LocalBinder();private ServiceConnection mConnectionHandler = null;Handler mHandler = new Handler();public ProviderService() {super(TAG, SASOCKET_CLASS);}@Overridepublic void onCreate() {super.onCreate();SA mAccessory = new SA();try {mAccessory.initialize(this);} catch (SsdkUnsupportedException e) {// try to handle SsdkUnsupportedExceptionif (processUnsupportedException(e) == true) {return;}} catch (Exception e1) {e1.printStackTrace();/** Your application can not use Samsung Accessory SDK. Your application should work smoothly* without using this SDK, or you may want to notify user and close your application gracefully* (release resources, stop Service threads, close UI thread, etc.)*/stopSelf();}}@Overridepublic IBinder onBind(Intent intent) {return mBinder;}@Overrideprotected void onFindPeerAgentsResponse(SAPeerAgent[] peerAgents, int result) {Log.d(TAG, "onFindPeerAgentResponse : result =" + result);}@Overrideprotected void onServiceConnectionRequested(SAPeerAgent peerAgent) {if (peerAgent != null) {Toast.makeText(getBaseContext(), R.string.ConnectionAcceptedMsg, Toast.LENGTH_SHORT).show();acceptServiceConnectionRequest(peerAgent);}}@Overrideprotected void onServiceConnectionResponse(SAPeerAgent peerAgent, SASocket socket, int result) {if (result == SAAgent.CONNECTION_SUCCESS) {if (socket != null) {mConnectionHandler = (ServiceConnection) socket;}} else if (result == SAAgent.CONNECTION_ALREADY_EXIST) {Log.e(TAG, "onServiceConnectionResponse, CONNECTION_ALREADY_EXIST");}}@Overrideprotected void onAuthenticationResponse(SAPeerAgent peerAgent, SAAuthenticationToken authToken, int error) {/** The authenticatePeerAgent(peerAgent) API may not be working properly depending on the firmware* version of accessory device. Please refer to another sample application for Security.*/}@Overrideprotected void onError(SAPeerAgent peerAgent, String errorMessage, int errorCode) {super.onError(peerAgent, errorMessage, errorCode);}private boolean processUnsupportedException(SsdkUnsupportedException e) {e.printStackTrace();int errType = e.getType();if (errType == SsdkUnsupportedException.VENDOR_NOT_SUPPORTED|| errType == SsdkUnsupportedException.DEVICE_NOT_SUPPORTED) {/** Your application can not use Samsung Accessory SDK. You application should work smoothly* without using this SDK, or you may want to notify user and close your app gracefully (release* resources, stop Service threads, close UI thread, etc.)*/stopSelf();} else if (errType == SsdkUnsupportedException.LIBRARY_NOT_INSTALLED) {Log.e(TAG, "You need to install Samsung Accessory SDK to use this application.");} else if (errType == SsdkUnsupportedException.LIBRARY_UPDATE_IS_REQUIRED) {Log.e(TAG, "You need to update Samsung Accessory SDK to use this application.");} else if (errType == SsdkUnsupportedException.LIBRARY_UPDATE_IS_RECOMMENDED) {Log.e(TAG, "We recommend that you update your Samsung Accessory SDK before using this application.");return false;}return true;}public class LocalBinder extends Binder {public ProviderService getService() {return ProviderService.this;}}public class ServiceConnection extends SASocket {public ServiceConnection() {super(ServiceConnection.class.getName());}@Overridepublic void onError(int channelId, String errorMessage, int errorCode) {}@Overridepublic void onReceive(int channelId, byte[] data) {if (mConnectionHandler == null) {return;}Calendar calendar = new GregorianCalendar();SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd aa hh:mm:ss.SSS");String timeStr = " " + dateFormat.format(calendar.getTime());String strToUpdateUI = new String(data);final String message = strToUpdateUI.concat(timeStr);new Thread(new Runnable() {public void run() {try {mConnectionHandler.send(getServiceChannelId(0), message.getBytes());Intent intent = new Intent(getBaseContext(), RingMeActivity.class);startActivity(intent);} catch (IOException e) {e.printStackTrace();}}}).start();}@Overrideprotected void onServiceConnectionLost(int reason) {mConnectionHandler = null;mHandler.post(new Runnable() {@Overridepublic void run() {Toast.makeText(getBaseContext(), R.string.ConnectionTerminateddMsg, Toast.LENGTH_SHORT).show();}});}}} - Buat Activity baru dengan nama RingMeActivity.
- Pada activity_ring_me.xml, tambahkan textview dan button seperti berikut.
1234567891011121314151617181920212223242526272829<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/colorPrimary"tools:context="com.dicoding.findphone.RingMeActivity"><TextViewandroid:id="@+id/text_notice"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:textSize="17sp"android:gravity="center"android:text="@string/your_phone_has_been_rung_by_your_accessory_device"/><Buttonandroid:id="@+id/stop"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/text_notice"android:layout_centerHorizontal="true"android:layout_marginTop="16dp"android:text="@string/ok"android:textColor="@color/colorAccent"android:background="@android:color/white"/></RelativeLayout> - Pada RingMeActivity.Java tambahkan kode berikut.
123456789101112131415161718192021public class RingMeActivity extends AppCompatActivity {Button stopButton;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_ring_me);final MediaPlayer player = MediaPlayer.create(getApplicationContext(),Settings.System.DEFAULT_RINGTONE_URI);player.start();stopButton = (Button) findViewById(R.id.stop);stopButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {player.stop();finish();}});}} - Buka AndroidManifest.xml dan tambahkan beberapa permission berikut.
123456789<uses-permission android:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /><uses-permission android:name="com.samsung.accessory.permission.ACCESSORY_FRAMEWORK" /><uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" /><uses-permission android:name="com.samsung.WATCH_APP_TYPE.Companion" /><uses-permission android:name="com.samsung.wmanager.ENABLE_NOTIFICATION" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> - Masih di AndroidManifest.xml, tambahkan services, receiver, dan meta-data berikut pada tag application.
12345678910111213141516171819<service android:name=".ProviderService" /><receiver android:name="com.samsung.android.sdk.accessory.RegisterUponInstallReceiver"><intent-filter><action android:name="com.samsung.accessory.action.REGISTER_AGENT" /></intent-filter></receiver><receiver android:name="com.samsung.android.sdk.accessory.ServiceConnectionIndicationBroadcastReceiver"><intent-filter><action android:name="com.samsung.accessory.action.SERVICE_CONNECTION_REQUESTED" /></intent-filter></receiver><meta-dataandroid:name="AccessoryServicesLocation"android:value="/res/xml/accessoryservices.xml" /><meta-dataandroid:name="GearAppType"android:value="tpk" /> - Terakhir sebelum aplikasi dijalankan, pastikan pada Run/Debug configuration sudah terpilih Nothing untuk Launch Option.
- Jalankan aplikasinya pada Smart Device kamu.
Kamu sudah selesai membuat 2 aplikasi yang saling terintegrasi. Silahkan buka aplikasi FindPhone pada Samsung Gear kamu dan touch button Ring My Phone. Jika kamu berhasil mengikuti beberapa step diatas, maka hasilnya akan seperti video dibawah ini.
Masih banyak fitur yang bisa kamu manfaatkan dari Accessory SDK. Silahkan ikuti akademinya pada https://www.dicoding.com/academies/37. Jika ada pertanyaan, saran atau masukan jangan sungkan untuk menuliskannya di kolom komentar.
Selamat belajar dan semoga bermanfaat. Jangan lupa kembangkan kreatifitas kamu.