--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file askuser-notification-client.h
+ * @author Piotr Sawicki <p.sawicki2@partner.samsung.com>
+ * @version 1.0
+ * @brief The declaration of the askuser-notification client API.
+ */
+
+#ifndef ASKUSER_NOTIFICATION_CLIENT_H
+#define ASKUSER_NOTIFICATION_CLIENT_H
+
+/**
+ * \name Status return codes
+ * @{
+ */
+
+/*! \brief indicating that the call was successful */
+#define ASKUSER_API_SUCCESS 0
+
+/*! \brief indicating that an unknown error occurred */
+#define ASKUSER_API_UNKNOWN_ERROR -1
+
+/*! \brief indicating that a memory allocation failed */
+#define ASKUSER_API_OUT_OF_MEMORY -2
+
+/*! \brief indicating that an invalid parameter was passed */
+#define ASKUSER_API_INVALID_PARAM -3
+
+/*! \brief indicating that a connection error occurred */
+#define ASKUSER_API_CONNECTION_ERROR -4
+
+/** @} */
+
+/**
+ * \name Types of file descriptor events
+ *
+ * @{
+ */
+
+/*! \brief a file descriptor is ready to read */
+#define ASKUSER_READ_EVENT (1 << 0)
+
+/*! \brief a file descriptor is ready to write */
+#define ASKUSER_WRITE_EVENT (1 << 1)
+
+/*! \brief an error has been detected on a file descriptor by an event loop or
+ * the API wants to inform that a file descriptor is to be closed
+ */
+#define ASKUSER_EMPTY_EVENTS 0
+
+/** @} */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct askuser_client askuser_client;
+
+/**
+ * \enum askuser_check_result
+ * Values indicating the result of an askuser_client_check_privilege() call.
+ *
+ * \var askuser_check_result::ASKUSER_CHECK_RESULT_ALLOW
+ * An application has a privilege.
+ *
+ * \var askuser_check_result::ASKUSER_CHECK_RESULT_DENY
+ * An application does not have a privilege.
+ *
+ * \var askuser_check_result::ASKUSER_CHECK_RESULT_ASK
+ * A user should be asked about whether grant privilege to an application or not.
+ */
+typedef enum {
+ ASKUSER_CHECK_RESULT_ALLOW,
+ ASKUSER_CHECK_RESULT_DENY,
+ ASKUSER_CHECK_RESULT_ASK,
+} askuser_check_result;
+
+/**
+ * \enum askuser_popup_result
+ * Values returned by popup.
+ *
+ * \var askuser_popup_result::ASKUSER_POPUP_RESULT_ALLOW_FOREVER
+ * A user granted a privilege to an application.
+ *
+ * \var askuser_popup_result::ASKUSER_POPUP_RESULT_DENY_FOREVER
+ * A user did not grant a privilege to an application.
+ *
+ * \var askuser_popup_result::ASKUSER_POPUP_RESULT_DENY_ONCE
+ * A user did not grant a privilege to an application for this
+ * particular query.
+ */
+typedef enum {
+ ASKUSER_POPUP_RESULT_ALLOW_FOREVER,
+ ASKUSER_POPUP_RESULT_DENY_FOREVER,
+ ASKUSER_POPUP_RESULT_DENY_ONCE,
+} askuser_popup_result;
+
+/**
+ * \enum askuser_call_cause
+ * Values indicating the reason passed to askuser_popup_response_callback.
+ *
+ * \var askuser_call_cause::ASKUSER_CALL_CAUSE_ANSWER
+ * Callback was called with a valid answer.
+ *
+ * \var askuser_call_cause::ASKUSER_CALL_CAUSE_ERROR
+ * Callback was called because of an error.
+ *
+ * \var askuser_call_cause::ASKUSER_CALL_CAUSE_FINALIZE
+ * Callback was called because askuser_client_finalize() had been called.
+ */
+typedef enum {
+ ASKUSER_CALL_CAUSE_ANSWER,
+ ASKUSER_CALL_CAUSE_ERROR,
+ ASKUSER_CALL_CAUSE_FINALIZE,
+} askuser_call_cause;
+
+
+/**
+ * \brief This callback function is called when the status of a file descriptor changes.
+ *
+ * A file descriptor changes when a client:
+ * - is ready to send a request (after calling: askuser_client_popup_request())
+ * - is ready to receive a response
+ *
+ * This function is crucial to implement an asynchronous API. An application should
+ * register its askuser_status_callback function to monitor file descriptors.
+ * In the body of this callback function, the application should configure its
+ * I/O multiplexing mechanism (select, poll, GLib main loop etc.) to wait for specified
+ * events (events parameter) which may occur on a file descriptor (fd parameter).
+ *
+ * \attention This callback is called from the askuser_client_process() function context.
+ *
+ * \attention The events and fd parameters passed in this callback should be
+ * stored on the application side. Application should use this stored information
+ * in every event loop cycle to configure its I/O multiplexing mechanism.
+ * It is due to the fact that the callback may not be called in every loop cycle for every
+ * askuser_client_process() call. For example, if the API wants to send some data,
+ * it calls the callback with the 'events' param having the ASKUSER_WRITE_EVENT flag set.
+ * Then, askuser_client_process() may be called multiple times until the data is sent.
+ * When this task is done, the callback is called with cleared ASKUSER_WRITE_EVENT,
+ * which means that the application should stop waiting for the WRITE event.
+ *
+ * Have a look at the below simplified code (managing of fd is ommited for better
+ * readability).
+ *
+ * \code
+ * int app_events_to_wait_for;
+ *
+ * void callback(int fd, int events, void *p_user_data)
+ * {
+ * app_events_to_wait_for = events;
+ * }
+ *
+ * void event_loop()
+ * {
+ * for (;;) {
+ * detected_events = wait_for_events(app_events_to_wait_for);
+ * askuser_client_process(client, fd, detected_events);
+ * }
+ * }
+ * \endcode
+ *
+ * \param[in] fd A file descriptor.
+ * \param[in] events It is a bit-field value compounds of ASKUSER_READ_EVENT
+ * or ASKUSER_WRITE_EVENT or both.
+ * Special value ASKUSER_EMPTY_EVENTS indicates that the
+ * file descriptor (fd) should be removed from a file
+ * descriptor set of an event loop mechanism.
+ * \param[in] p_user_data User specific data passed to askuser_client_initialize().
+ */
+typedef void (*askuser_status_callback) (int fd, int events, void *p_user_data);
+
+/**
+ * \brief This callback function is called when a client receives a response
+ * upon calling askuser_client_popup_request().
+ *
+ * \attention This callback is called from the askuser_client_process() function context.
+ *
+ * \param[in] request_id A number identifying the request. It will be equal to
+ * the value of *p_request_id generated by a corresponding
+ * askuser_client_popup_request() function call.
+ * \param[in] cause A value representing the reason why this callback has
+ * been called.
+ * \param[in] result It is a result of response to request created by
+ * askuser_client_popup_request(). This should be
+ * interpreted as a valid value only if cause is equal to
+ * askuser_call_cause::ASKUSER_CALL_CAUSE_ANSWER.
+ * \param[in] p_user_data User specific data, this parameter was previously
+ * passed to askuser_client_popup_request().
+ */
+typedef void (*askuser_popup_response_callback) (int request_id,
+ askuser_call_cause cause,
+ askuser_popup_result result,
+ void *p_user_data);
+
+/**
+ * \brief Description
+ * Initialize askuser-notification client. It allocates structure and
+ * initializes it using a given status callback and user data.
+ *
+ * \par Purpose:
+ * This API function must be called prior to any call of the other
+ * askuser-notification client functions.
+ *
+ * \par Typical use case:
+ * It should be called before entering an event loop and before calling any
+ * other askuser-notification client API function.
+ *
+ * \par Method of function operation:
+ * This API function initializes inner library structures and in case of success
+ * returns askuser_client structure.
+ *
+ * \par Sync (or) Async:
+ * This is a synchronous API.
+ *
+ * \par Thread-safety:
+ * This function is NOT thread-safe.
+ *
+ * \par Important notes:
+ * Structure askuser_client created by a askuser_client_initialize() call
+ * should be released by calling askuser_client_finalize().
+ *
+ * \param[out] pp_client A placeholder for a newly created askuser_client
+ * structure. The pp_client is valid only if this
+ * function returns ASKUSER_API_SUCCESS.
+ * \param[in] status_callback A callback function which will be called every
+ * time when some file descriptor belonging to the
+ * askuser_client structure changes its state.
+ * \param[in] p_user_data User specific data which will be passed to the
+ * status_callback function.
+ * Set NULL if you don't use user data.
+ *
+ * \return ASKUSER_API_SUCCESS on success
+ * \return a negative value in case of an error (see "Status return codes")
+ */
+int askuser_client_initialize(askuser_client **pp_client,
+ askuser_status_callback status_callback,
+ void *p_user_data);
+
+/**
+ * \brief Description
+ * Release instance of the askuser_client structure. It releases all resources
+ * associated with askuser_client structure.
+ *
+ * \par Purpose:
+ * This API function must be called to release all resources associated with
+ * askuser_client structure.
+ *
+ * \par Typical use case:
+ * This API function should be called when the askuser-notification client
+ * functionality is no more used by an application
+ * (e.g. when the application finishes).
+ *
+ * \par Method of function operation:
+ * This API function releases all internal resources and deallocates the
+ * askuser_client structure. When there are pending requests, registered
+ * askuser_response_callback functions will be called with an appropriate
+ * status code: askuser_call_cause::ASKUSER_CALL_CAUSE_FINALIZE.
+ *
+ * \par Sync (or) Async:
+ * This is a synchronous API.
+ *
+ * \par Thread-safety:
+ * This function is NOT thread-safe.
+ *
+ * \par Important notes:
+ * After calling this function on a particular askuser_client structure,
+ * no subsequent calls of askuser_client_finalize() should be performed on
+ * the same structure.
+ *
+ * \param[out] p_client An instance of the askuser_client structure,
+ * previously created by askuser_client_initialize().
+ */
+void askuser_client_finalize(askuser_client *p_client);
+
+/**
+ * \brief Description
+ * This function process R/W events that occurred on a file descriptor associated
+ * with a specific askuser_client structure. All statuses and errors which occur
+ * on the file descriptor will be passed to a callback function registered by
+ * invoking askuser_client_initialize().
+ *
+ * \par Purpose:
+ * This API function is called to process read and write events which occurred
+ * on a file descriptor. In result of calling this function an appropriate
+ * callback is executed: askuser_status_callback or askuser_popup_response_callback.
+ *
+ * \par Typical use case:
+ * The event loop of an application waits for events which may occur on file descriptors
+ * previously registered by askuser_status_callback. When an event occurs then the event
+ * loop should call this function passing an askuser_client structure, a file
+ * descriptor on which the event occurred and events (a bit-field value compounds of
+ * ASKUSER_READ_EVENT and ASKUSER_WRITE_EVENT).
+ *
+ * \par Method of function operation:
+ * \parblock
+ * This function sends pending requests (ASKUSER_WRITE_EVENT), receives all responses
+ * from the askuser-notification service (ASKUSER_READ_EVENT). In result of these
+ * actions an appropriate callback is executed (askuser_popup_response_callback,
+ * or askuser_status_callback).
+ * \endparblock
+ *
+ * \par Sync (or) Async:
+ * This is a synchronous API.
+ *
+ * \par Thread-safety:
+ * This function is NOT thread-safe.
+ *
+ * \param[in] p_client An instance of the askuser_client structure, previously
+ * created by askuser_client_initialize().
+ * \param[in] fd A file descriptor.
+ * \param[in] events It is a bit-field value compounds of ASKUSER_READ_EVENT
+ * and ASKUSER_WRITE_EVENT, which represents the detected
+ * events on that fd. The event loop mechanism should
+ * pass **ASKUSER_EMPTY_EVENTS** if it detects an error
+ * on the file descriptor.
+ *
+ * \return ASKUSER_API_SUCCESS on success
+ * \return a negative value in case of an error (see "Status return codes")
+ */
+int askuser_client_process(askuser_client *p_client, int fd, int events);
+
+/**
+ * \brief Description
+ * This function is called to check if an application has access to a particular
+ * privilege.
+ *
+ * \par Purpose:
+ * This API function should be called if an application wants to check if it has
+ * access to a given privilege.
+ *
+ * \par Sync (or) Async:
+ * This is a synchronous API.
+ *
+ * \par Thread-safety:
+ * This function is NOT thread-safe.
+ *
+ * \param[in] p_client An instance of the askuser_client structure previously
+ * created by askuser_client_initialize().
+ * \param[in] privilege Privilege that is to be checked.
+ * \param[out] p_result The result of a privilege check.
+ *
+ * \return ASKUSER_API_SUCCESS on success
+ * \return a negative value in case of an error (see "Status return codes")
+ */
+int askuser_client_check_privilege(askuser_client *p_client, const char *privilege,
+ askuser_check_result *p_result);
+
+/**
+ * \brief Description
+ * This function is called to determine a privacy privilege .
+ *
+ * \par Purpose:
+ * This API function should be called if an application wants to determine a privacy
+ * privilege. When this function is called, the askuser-notification service shows
+ * an appropriate UI dialog box (popup) with a question. After user's decision, the
+ * service modifies sends the response back to the application.
+ * The application is informed about user's decision by calling
+ * askuser_popup_response_callback.
+ *
+ * \par Method of function operation:
+ * If the result of calling askuser_client_check_privilege() is
+ * askuser_check_result::ASKUSER_CHECK_RESULT_ASK, the application should call
+ * this function to determine whether a user allows an application to use
+ * a particular privilege.
+ *
+ * \par Sync (or) Async:
+ * This is an asynchronous API.
+ *
+ * \par Thread-safety:
+ * This function is NOT thread-safe.
+ *
+ * \param[in] p_client An instance of the askuser_client structure
+ * previously created by askuser_client_initialize().
+ * \param[in] privilege A privilege for which a popup must be shown.
+ * \param[in] response_callback A callback function called when the API receives
+ * a response.
+ * \param[in] p_user_data User specific data which will be passed to
+ * the registered response_callback.
+ * Set to NULL if you don't use user data.
+ * \param[out] p_request_id An identifier of a request generated by the API.
+ * Set NULL if you don't use a request ID.
+ *
+ * \return ASKUSER_API_SUCCESS on success
+ * \return a negative value in case of an error (see "Status return codes")
+ */
+int askuser_client_popup_request(askuser_client *p_client, const char *privilege,
+ askuser_popup_response_callback response_callback,
+ void *p_user_data, int *p_request_id);
+
+/**
+ * Example
+ *
+ * NOTICE: Everything with app prefix is a part of a hypothetical
+ * application framework.
+ *
+ * \code
+ * void ask_status_callback(int fd, int events, void *p_user_data)
+ * {
+ * assert(p_user_data != NULL);
+ * app_context *app = (app_context *) p_user_data;
+ * // Note that events == 0 means that this fd should be
+ * // removed from a monitored file descriptor set.
+ * app_update_fds(app, fd, app_askuser_to_app_events(events));
+ * }
+ *
+ * void ask_popup_response_callback(int request_id, askuser_call_cause cause,
+ * askuser_popup_result result, void *p_user_data)
+ * {
+ * assert(p_user_data != NULL);
+ * app_context *app = (app_context *) p_user_data;
+ * app_callback callback = app_get_callback(app, request_id);
+ *
+ * switch (cause) {
+ * case ASKUSER_CALL_CAUSE_ANSWER:
+ * callback(app, askuser_to_app_popup_result(result));
+ * break;
+ * case ASKUSER_CALL_CAUSE_FINALIZE:
+ * callback(app, APP_IS_CLOSING);
+ * break;
+ * case ASKUSER_CALL_CAUSE_ERROR:
+ * // handle errors
+ * callback(app, APP_ASKUSER_ERROR_OCCURED);
+ * break;
+ * }
+ *
+ * app_unregister_callback(app, request_id);
+ * }
+ *
+ * void app_check_privilege(app_context *app, const char *privilege, app_callback callback);
+ * {
+ * int status;
+ * int request_id;
+ * askuser_check_result result;
+ *
+ * assert(app != NULL);
+ * askuser_client *client = app_get_askuser_client(app);
+ *
+ * status = askuser_client_check_privilege(client, &result);
+ * if (status != ASKUSER_API_SUCCESS) {
+ * // handle errors
+ * return;
+ * }
+ *
+ * switch (result) {
+ * case ASKUSER_CHECK_RESULT_ALLOW:
+ * // adjust GUI to reflect that the app has access to a
+ * // specific resource
+ * break;
+ * case ASKUSER_CHECK_RESULT_DENY:
+ * // adjust GUI to reflect that the app doesn't have access to a
+ * // specific resource
+ * break;
+ * case ASKUSER_CHECK_RESULT_ASK:
+ * status = askuser_client_popup_request(client, privilege,
+ * ask_popup_response_callback, app, &request_id);
+ * if (status != ASKUSER_API_SUCCESS) {
+ * //handle errors
+ * return;
+ * }
+ * app_register_callback(app, callback, request_id);
+ * break;
+ * }
+ * }
+ *
+ *
+ * void main_loop(app_context *app)
+ * {
+ * int status
+ * int fd;
+ * askuser_client *client = NULL;
+ *
+ * assert(app != NULL);
+ *
+ * status = askuser_client_initialize(&client, ask_status_callback, app);
+ * if (status != ASKUSER_API_SUCCESS) {
+ * // handle errors
+ * return;
+ * }
+ *
+ * app_set_askuser_client(app, client);
+ *
+ * // event loop
+ * for (;;) {
+ * app_wait_for_events(app);
+ *
+ * app_for_each_active_fd(app, fd) {
+ * if (app_is_askuser_fd(app, fd)) {
+ * app_events events = app_get_fd_events(app, fd);
+ * askuser_client_process(client, fd, app_to_askuser_events(events));
+ * }
+ * // process other file descriptors not related to askuser
+ * }
+ * }
+ *
+ * askuser_client_finalize(client);
+ * }
+ * \endcode
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ASKUSER_NOTIFICATION_CLIENT_H */