{"_id":"5abba5c00117970012ba9b7e","category":{"_id":"5abba5c00117970012ba9b72","version":"5abba5c00117970012ba9b6e","project":"55093b151c38c50d00611894","__v":0,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-03-18T09:01:41.604Z","from_sync":false,"order":4,"slug":"code-examples","title":"Code Examples"},"project":"55093b151c38c50d00611894","user":"55093bd84510200d00adf3c7","version":{"_id":"5abba5c00117970012ba9b6e","project":"55093b151c38c50d00611894","__v":2,"createdAt":"2018-03-28T14:25:04.622Z","releaseDate":"2018-03-28T14:25:04.622Z","categories":["5abba5c00117970012ba9b6f","5abba5c00117970012ba9b70","5abba5c00117970012ba9b71","5abba5c00117970012ba9b72","5ace17b040606a0003eabc75"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"2.0.0","version":"2.0"},"__v":0,"updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-30T10:21:36.685Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"settings":"","results":{"codes":[]},"auth":"required","params":[],"url":""},"isReference":false,"order":11,"body":"#Introduction #\n\nThis is a quick start to using the ISKN API  on Android studio. At the end of this tutorial, the developer should be capable to create an Android application based on the ISKN API and master the most important concepts about the API architecture and usage. This involves listing the available slates, connecting to a slate, requesting information about the slate as well as subscribing to the ISKN services and decoding slate data.\nThe following tutorial assumes that the developer has already installed Android studio (Android Studio 3.0.1 version - API 21: Android 5.0 (Lollipop) as Minimum SDK version).\n\n## 1.General concepts\n### 1.1 Request App permissions\n\nTo maintain security for the system and users, Android requires apps to request permission before they can use certain system and features.\nYou declare that your app needs a permission by listing the permission in the app manifest and then requesting that the user approve each permission at runtime (on Android 6.0 and higher).\nSince, the API uses the Bluetooth features, several permissions must be granted. This can be done by using the following entries in the application manifest:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<uses-permission android:name=\\\"android.permission.BLUETOOTH\\\"/>\\n<uses-permission android:name=\\\"android.permission.BLUETOOTH_ADMIN\\\"/>\\n<uses-permission android:name=\\\"android.permission.ACCESS_FINE_LOCATION\\\"/>\\n<uses-permission android:name=\\\"android.permission.ACCESS_COARSE_LOCATION\\\"/>\\n<uses-feature android:name=\\\"android.hardware.bluetooth_le\\\" android:required=\\\"true\\\"/>\\n\",\n      \"language\": \"xml\"\n    }\n  ]\n}\n[/block]\n### 1.2 Import API packages\nTo use the ISKN API, you need these import statements:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"import com.iskn.isknApi.*;\\nimport com.iskn.isknApi.events.*;\\nimport com.iskn.isknApi.bleScanner.*;\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n### 1.3 The Slate Manager\nThe SlateManager class is the main gateway to communicate with Slates. It provides both scan and communication functionalities through a set of methods such as connect, startScan, subscribe … So it’s required to create a SlateManager instance on the Activity’s onCreate method of the Android app.\n\n### 1.4 The Listener interfaces\nIn order to receive Slate data, the application main class needs to implement two interfaces: Listener interface and BLE_Scan_Listener interface. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"public class MainActivity implements Listener, BLE_Scan_Listener{\\n// Do stuff…\\n}\\n// In this code sample MainActivity class implements both the Listener and BLE_Scan_Listener interfaces\\n\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nThe reception of data is provided asynchronously via the two Listeners. Each one offers a collection of abstract methods. Unless the class that implements the interfaces is abstract, all the methods of the interfaces need to be defined in the class.\n- Listener abstract methods: \n + connectionStatusChanged method\nIt is called whenever the Slate connection status changes (connected or disconnected).\n + processEvent method\nIt is called whenever an event is sent from the slate (for example, new pen position data has arrived).\n- BLE_Scan_Listener  abstract methods:\nImplements methods that are called when new slates are discovered, when the discovery fails and when the discovery is finished. \n + newDeviceFound method.\n + notify method.\n + scanFailed method.\n + scanFinished method.\nThe use of these methods will be explained in the next section.\n\n### 1.5 The scan process\nThe scan for slates is triggered by a call to the **startScan** method of the **SlateManager** class.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"slateManager.startScan(MainActivity.this);\\n\\n// “MainActivity.this” is an instance of a class that implements the BLE_Scan_Listener\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nOnce the scan is launched, the main class that implements the **BLE_Scan_Listener** interface will receive different events through the inherited abstract methods. \n\n## 2.Slates discovery\nWhen a new Slate is discovered, the implemented  **newDeviceFound**  method is called:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \":::at:::Override\\npublic void newDeviceFound(final BluetoothDevice bluetoothDevice){\\n// Do stuff…\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nThis methods takes a Bluetooth device as parameter. The discovered Bluetooth device can be added to a list of discovered Slates or we can connect to it directly using its name or address.\n\n### 2.1 Scan status\nThe scan process may have two status states, scan finished or scan failed.\nWhen the scan is finished, the scanFinished method is called:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void scanFinished() {\\n// The scan can be relaunched if necessary\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nAnd if the scan fails, the scanFailed method is called:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void scanFailed(int ) {\\n// The user can be notified by displaying a message on the screen \\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n### 2.2 Scan notifications\nDuring the scan process the user needs to be notified of some specific issues for example if the Bluetooth is not supported on the used device or if the Bluetooth activation is required.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"public void notify(final BleScanner_Event bleScanner_event, String info){\\n// The user can be notified by displaying a message on the screen \\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nThe main events are:\n- BLESCANNER_EVENT_BLE_NOT_SUPPORTED: This event is sent if the device does not support Bluetooth.\n- BLESCANNER_EVENT_ACTIVATION_REQUIRED: This event is sent if the activation of Bluetooth is required.\n- BLESCANNER_EVENT_BLE_SCAN_STARTED: This event is sent when the Bluetooth scan has started.\n\n### 2.3 The connection process\nThe connection to the Slate is triggered by a call to the connect method of the SlateManager class.\n\n#### 2.3.1 Listener registration\nBefore calling the connect method, it is required to register the listener object in order to receive the Slate events.\nThis can be done right after creating the SlateManager object.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// Create SlateManager object\\nslateManager=new SlateManager(this);\\n// Register the MainActivity class as a listener\\nslateManager.registerListener(this);\\n\\n// “this” is the listener instance\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n#### 2.3.2 Connection request\nThe connection request can be sent immediately when a device is discovered which means when the **newDeviceFound** method is called. \n\nAs mentioned before, the developer can either add the discovered Bluetooth device to a list of discovered Slates or connect to it directly using its name or address.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"slateManager.connect(BluetoothDevice device);\\n\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nIt is important to know that the connect method is overloaded. So it can be used without a Bluetooth device parameter. In this case the app will connect to the first discovered Slate.\n\nWhen the Slate is connected, the **connectionStatusChanged** method is called.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"public void connectionStatusChanged(final boolean connected){\\n// in this case, the boolean connected is true\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nIf the connection succeeds, the application can subscribe to the Slate services or request individual information like the Slate description or the battery status.\n\n#### 2.3.3 Disconnection request  \nJust as the connection, the disconnection is simply executed by calling:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"slateManager.disconnect();\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nOnce disconnected, the **connectionStatusChanged** method is called with false as parameter.\n\n### 2.4 The communication workflow\nOnce connected, the Slate waits for application requests.\nThe requests are split into two types:\n\n#### 2.4.1 Single requests\nThe Slate replies to those requests instantaneously by sending the requested information.\nFor example, the application may request device information (its name, the size of the capture area...) or battery status.\nTo send a request to the Slate you can use the **request** method of the **SlateManager** class:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"slateManager.request(SlateManager.SingleRequestBlockType.REQ_STATUS);\\n // In this example the request block type is REQ_STATUS\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n#### 2.4.2 Subscription requests\n\nThe application can subscribe to one or more Slate events. There are many events that can be generated by the Slate, such as a pen detection event, that occurs when a pen enters or leaves the Slate view field. When a pen moves, the Slate generates events such as the position, orientation and contact of the pen tip.\nTo send subscription to the Slate you can use the subscribe method of the **SlateManager** class:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"slateManager.subscribe(<One or a combination of AutoBlockType separated by |>)\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n#### 2.4.3 Handle events reception\nThe requests and subscriptions sent to the Slate are managed asynchronously. \nWhen a response is sent from the slate, the processEvent method of the listener is called with an Event object:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"public void processEvent(final Event event, int i) {\\n\\n    runOnUiThread(new Runnable() {\\n        @Override\\n        public void run() {\\n            switch(event.getType()){\\n                case EVT_STATUS: {\\n                    EventStatus evt = (EventStatus) event; \\n\\t\\t     // Do stuff…\\n                    break;\\n                }\\n                case EVT_DESCRIPTION: {\\n                    EventDescription evt = (EventDescription) event;\\n\\t\\t     // Do stuff…\\n                    break;\\n                }\\n                case EVT_PEN_3D: {\\n                    EventPen3D evt = (EventPen3D) event;\\n\\t\\t     // Do stuff…\\n                    break;\\n                }\\n                case EVT_SOFTWARE:{\\n                    EventSoftware evt = (EventSoftware) event;\\n\\t\\t     // Do stuff…\\n                    switch(evt.getSoftwareEventType()){\\n                        case SE_OBJECT_IN: \\n\\t\\t\\t     <User Code Here>\\n                            break;\\n                        case SE_OBJECT_OUT: \\n\\t\\t// Do stuff…\\n                            break;\\n                    }\\n                    break;}}} });\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nIn the sample code above the getType method of the Event class is used.\nIt is then possible to cast the event to the right type and then extract the needed information.\n\n## 3.The Android test application\n\nIn this section, we will focus on creating a simple application that uses the concepts presented above in order to interact with slates.\n\n### 3.1 The application overview\n\nWhen launched, the interface presented in Figure 1 appears. \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/aaffb54-Picture1.png\",\n        \"Picture1.png\",\n        977,\n        610,\n        \"#2a3a7b\"\n      ],\n      \"caption\": \"Figure 1 First view\"\n    }\n  ]\n}\n[/block]\nThe **START THE SCAN** button is pressed, the tablet starts scanning for Slates.\nBefore scanning, make sure that the slate is powered on and the side led is blinking in blue.\n\nWhen a Slate is discovered, it appears in the devices list. The MAC address of the Slate is displayed as well as its name. \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/ee50d0d-Picture2.png\",\n        \"Picture2.png\",\n        964,\n        602,\n        \"#2a3a79\"\n      ],\n      \"caption\": \"Figure 2 Slate discovered view\"\n    }\n  ]\n}\n[/block]\nSelect the slate to connect to it. \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/5df8dc8-Picture3.png\",\n        \"Picture3.png\",\n        972,\n        606,\n        \"#2b3c7b\"\n      ],\n      \"caption\": \"Figure 3 Connected slate view\"\n    }\n  ]\n}\n[/block]\nOnce the Slate is connected, a bunch of information are displayed in the console:\nTwo new buttons appear: **REFRESH** and **DISCONNECT**. The first enables refreshing the slate in case of magnetic disturbances and the second is used to disconnect from it. Finally, the battery status is displayed.\nNow the slate is ready to send data to the application. In this app, we have subscribed to the Pen3D service which provides the 3 coordinates of the pen tip, the pen surface contact status as well as the angles that describe the pen orientation.\nThe pen tip coordinates are displayed on the screen if the pen is placed in the field of view of the slate. When the pen touches the paper, the pen3D text turns red.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/f28dc30-Picture4.png\",\n        \"Picture4.png\",\n        931,\n        581,\n        \"#2b3d7a\"\n      ],\n      \"caption\": \"Figure 4 Pen3D position display page\"\n    }\n  ]\n}\n[/block]\nWhen **REFRESH** button is clicked, the slate is refreshed (magnetic disturbances are compensated). Before doing this step, please move away the pen from the Slate surface before pressing this button.\nTo disconnect from the Slate the **DISCONNECT** button can be used. \n\n### 3.2 Creating the application\n\nCreate an Android application and select **API 21: Android 5.0 (Lollipop)** as a **minimum SDK **version when asked. You can select a higher version if you wish, but the minimum allowed by the ISKN_API is 21.  \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/115b2ee-Picture5.png\",\n        \"Picture5.png\",\n        854,\n        600,\n        \"#63625f\"\n      ],\n      \"caption\": \"Figure 5 Target Android Devices\"\n    }\n  ]\n}\n[/block]\nOnce the activity is created, we have to add the ISKN API module, by selecting File>New>New Module… \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/107dafc-Picture6.png\",\n        \"Picture6.png\",\n        954,\n        293,\n        \"#e5e8eb\"\n      ],\n      \"caption\": \"Figure 6 Add a Module\"\n    }\n  ]\n}\n[/block]\nSelect import JAR/AAR package and hit next.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/0cde75d-Picture7.png\",\n        \"Picture7.png\",\n        908,\n        670,\n        \"#646363\"\n      ],\n      \"caption\": \"Figure 7 Import JAR/AAR Package\"\n    }\n  ]\n}\n[/block]\nSelect the iskn_api-release.aar (release version) or iskn_api-debug.aar (debug version) then hit Finish. \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/f3dd6f9-Picture8.png\",\n        \"Picture8.png\",\n        968,\n        689,\n        \"#eaeaea\"\n      ]\n    }\n  ]\n}\n[/block]\nMake sure the library is listed at the top of your **settings.gradle** file, as shown here for a library named “iskn_api-release”:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"include ':app', ‘:iskn_api-release’\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]\nOpen the app module's **build.gradle** file and add a new line to the dependencies block as shown in the following snippet:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"dependencies {\\n    compile project(\\\":iskn_api-release\\\")\\n}\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]\nClick **Sync Project with Gradle Files.**\nThe project is ready to use the ISKN API.\n\n### 3.3\tImport library items\n\nAs mentioned before, we start by adding the API import statements:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"import com.iskn.isknApi.*;\\nimport com.iskn.isknApi.events.*;\\nimport com.iskn.isknApi.bleScanner.*;\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n3.4\tAdd Listeners implementations to the activity\n\nNow add the two needed listeners implementation to the Activity.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"public class MainActivity extends AppCompatActivity  implements Listener, BLE_Scan_Listener{\\n…\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nYou need also to implement the listeners’ methods:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"//  ===================================== //\\n//      Ble_Scan_Listener methods\\n//  ===================================== //\\n\\n@Override\\npublic void newDeviceFound(final BluetoothDevice bluetoothDevice) {\\n// Do stuff…\\n}\\n\\n@Override\\npublic void notify(final BleScanner_Event bleScanner_event, String s) {\\n// Do stuff…\\n}\\n\\n@Override\\npublic void scanFailed(int i) {\\n// Do stuff…\\n}\\n\\n@Override\\npublic void scanFinished() {\\n// Do stuff…\\n}\\n\\n//=====================================//\\n//     Listener methods\\n//  ===================================== //\\n@Override\\npublic void connectionStatusChanged(final boolean connected) {\\n   // Do stuff…\\n}\\n\\n@Override\\npublic void processEvent(final Event event, int i) {\\n   // Do stuff…\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n### 3.5 Runtime permission granting\n\nAs mentioned above, it’s mandatory to list the needed permissions in the app manifest.\nFurthermore, for SDK versions higher or equal to Marshmallow, it is necessary to ask for the **COARSE_LOCATION** permission in order to be able to use Bluetooth connection.\nWe do this in runtime by using this code:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// Request permission to access location\\nif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\\n    requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nThis code should be added in the activity onCreate  method before creating the SlateManager object.\n\n### 3.6 Create the Slate Manager\n\nDeclare a private (or public) member object of type SlateManager without initialising it:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"private SlateManager slateManager;\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nCreate the Slate Manager object in the onCreate method of the activity as follows:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// Create SlateManager object\\nslateManager=new SlateManager(this);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nNow you need to register the activity as the main listener so that we can receive events after the connection to the slate. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// Register the MainActivity class as a listener\\nslateManager.registerListener(this);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n### 3.7 Start Scanning\n\nNow the scan can be started. The startScan method in the onClick event listener of the **START SCAN** button:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"btnScan.setOnClickListener(new View.OnClickListener() {\\n    @Override\\n    public void onClick(View v) {\\n        llConnection.setVisibility(View.GONE);\\n        // Rest the list content\\n        items.clear();\\n        adapter.notifyDataSetChanged();\\n        // Start scanning for devices\\n        slateManager.stopScan();\\n        slateManager.startScan(MainActivity.this);\\n        appendInfo(\\\"Scanning...\\\\n\\\");\\n    }\\n});\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nHere we gave the **startScan** method the current activity as a parameter so it receives all the scan events.\n\n### 3.8 New device found event\n\nNow whenever a new Slate is found, add it to the list of the discovered Slates:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void newDeviceFound(final BluetoothDevice bluetoothDevice) {\\n    runOnUiThread(new Runnable() {\\n        @Override\\n        public void run() {\\n            final BluetoothDevice p_device=bluetoothDevice;\\n            appendInfo( \\\"Device \\\"+p_device.getName()+\\\" found\\\\n\\\");\\n            if(p_device.getName()!=null) {\\n                items.add(p_device.getName()+\\\" : \\\"+p_device.getAddress());\\n            }\\n            else\\n            {\\n                items.add(\\\"No Name : \\\"+p_device.getAddress());\\n            }\\n            adapter.notifyDataSetChanged();\\n        } });\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n### 3.9 Connect to the selected Slate\n\nWhen the user select a Slate among the list, the scan process is stopped and a connection request is sent via the connect method of the SlateManager object.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// When a device is selected, we connect to it\\nlstDevices.setOnItemClickListener(new AdapterView.OnItemClickListener() {\\n    @Override\\n    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\\n        // Stop scanning\\n        slateManager.stopScan();\\n\\n        // Connect to the selected device\\n        slateManager.connect(slateManager.getDeviceByIndex(position));\\n        btnScan.setVisibility(GONE);\\n        appendInfo(\\\"Connecting...\\\\n\\\");\\n    }\\n});\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nNotice that we fetch the device by its index in the list.\nIf connection succeeded, the method connectionStatusChanged is called with the connected parameter set to true.\n\n### 3.10 Request information and subscribe to events\n\nIn the connectionStatusChanged method, we can request information (Slate description as well as its status) and subscribe to useful services:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void connectionStatusChanged(final boolean connected) {\\n    runOnUiThread(new Runnable() {\\n        @Override\\n        public void run() {\\n            if (connected) {\\n                slateManager.request(SlateManager.SingleRequestBlockType.REQ_DESCRIPTION);\\n                slateManager.request(SlateManager.SingleRequestBlockType.REQ_STATUS);\\n\\n                slateManager.subscribe(SlateManager.AutoBlockType.AUTO_STATUS.type() |\\n                        SlateManager.AutoBlockType.AUTO_PEN_3D.type() |\\n                        SlateManager.AutoBlockType.AUTO_HARDWARE_EVENTS.type() |\\n                        SlateManager.AutoBlockType.AUTO_SOFTWARE_EVENTS.type());\\n\\n                device = slateManager.getDevice();\\n                llConnection.setVisibility(View.VISIBLE);\\n            } else {\\n                txtInfos.setText(\\\"\\\");\\n                appendInfo(txtInfos.getText() + \\\"Disconnected from \\\" + device.getDeviceName() + \\\"\\\\n\\\");\\n                llConnection.setVisibility(GONE);\\n                btnScan.setVisibility(VISIBLE);\\n            }\\n        }\\n    });\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nNotice that we use the Activity’s runOnUiThread method. In fact the ISKN API methods are executed on a worker thread. But, when the time comes to update the UI we must “return” to the Main Thread, as only he’s allowed to touch and update the application UI.\nA common way to achieve this is to call the Activity’s runOnUiThread method:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"runOnUiThread(new Runnable() {\\n     void run() {\\n         // Do stuff…\\n     }\\n});\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n### 3.11\tReceive and process events\nOnce we are subscribed to events, any time one of these events occur, the processEvent method is called. Here is an example of parsing and using the received information. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void processEvent(final Event event, int i) {\\n    // All ISNK related handlers need to run their code on tne main thread if they touch the ui\\n    // since these methods are called from another thread\\n    runOnUiThread(new Runnable() {\\n        @Override\\n        public void run() {\\n            switch(event.getType()){\\n                case EVT_STATUS: {\\n                    EventStatus evt = (EventStatus) event;\\n                    if(evt.getBattery()<10)\\n                        txtBattery.setTextColor(Color.RED);\\n                    else\\n                        if(evt.getBattery()<70)\\n                            txtBattery.setTextColor(Color.rgb(255,165,0));\\n                        else\\n                            txtBattery.setTextColor(Color.GREEN);\\n                    txtBattery.setText(\\\"Battery :\\\"+evt.getBattery()+\\\"%  \\\"+(evt.isBatteryInCharge()==1?\\\"Charging\\\":\\\"\\\"));\\n                    appendInfo( \\\"Battery :\\\" + evt.getBattery()+\\\"%\\\\n\\\");\\n                    appendInfo( \\\"Battery is charging ? \\\" + (evt.isBatteryInCharge()==1?\\\"Yes\\\":\\\"NO\\\")+\\\"\\\\n\\\");\\n                    break;\\n                }\\n                case EVT_DESCRIPTION: {\\n                    EventDescription evt = (EventDescription) event;\\n                    Rect activeZone=evt.getActiveZone();\\n                    Size SlateSize=evt.getSlateSize();\\n                    String name=evt.getDeviceName();\\n                    appendInfo( \\\"Connected to \\\" + name+\\\"\\\\n\\\");\\n                    appendInfo( \\\"Firmware version :\\\" + evt.getFirmwareVersion()+\\\"\\\\n\\\");\\n                    appendInfo( \\\"Slate Size (mm): \\\" +\\\"  width : \\\"+SlateSize.getWidth()+\\\" height : \\\"+SlateSize.getHeight()+\\\"\\\\n\\\");\\n                    appendInfo( \\\"Active Zone (mm): \\\" +\\\" left : \\\"+activeZone.getLeft()+\\\" top : \\\"+activeZone.getTop()+\\\" width : \\\"+activeZone.getWidth()+\\\" height : \\\"+activeZone.getHeight()+\\\"\\\\n\\\");\\n                    break;\\n                }\\n                case EVT_PEN_3D: {\\n                    EventPen3D evt = (EventPen3D) event;\\n                    Vector3D vec=evt.getPosition();\\n                    if(evt.Touch())\\n                        txtPos.setTextColor(Color.RED);\\n                    else\\n                        txtPos.setTextColor(Color.GREEN);\\n                    txtPos.setText(\\\"Pen 3D : \\\" + vec.getPosX() +\\\",\\\"+vec.getPosY()+vec.getPosZ()+\\\"\\\\n\\\");\\n                    break;\\n                }\\n                case EVT_SOFTWARE:{\\n                    EventSoftware evt = (EventSoftware) event;\\n                    switch(evt.getSoftwareEventType()){\\n                        case SE_OBJECT_IN:\\n                            appendInfo( \\\"Pen \\\"+ evt.getObjectID() +\\\" in\\\\n\\\");\\n                            break;\\n                        case SE_OBJECT_OUT:\\n                            appendInfo( \\\"Pen \\\"+ evt.getObjectID() +\\\" out\\\\n\\\");\\n                            break;\\n                    }\\n                    break;\\n                }\\n                case EVT_HARDWARE: {\\n                    EventHardware evt = (EventHardware) event;\\n                    switch (evt.getHardwareEventType()){\\n                        case HE_BUTTON1_PRESSED:\\n                            appendInfo( \\\"Button 1 pressed\\\\n\\\");\\n                            break;\\n                        case HE_BUTTON2_PRESSED:\\n                            appendInfo( \\\"Button 2 pressed\\\\n\\\");\\n                            break;\\n                        case HE_BUTTON1_LONGPRESS:\\n                            appendInfo( \\\"Button 1 long pressed\\\\n\\\");\\n                            break;\\n                        case HE_BUTTON2_LONGPRESS:\\n                            appendInfo( \\\"Button 2 long pressed\\\\n\\\");\\n                            break;\\n                        case HE_UNKNOWN:\\n                            appendInfo( \\\"Unknown hardware event\\\\n\\\");\\n                            break;\\n                        case HE_REFRESH_DONE:\\n                            appendInfo( \\\"Slate refresh is done\\\\n\\\");\\n                            break;\\n                        default:\\n                            appendInfo( \\\"Unknown hardware evnt \\\\n\\\");\\n                            break;\\n                    }\\n                    break;\\n                }\\n                case EVT_LOC_QUALITY:{\\n                    EventLocQuality evt=(EventLocQuality)event;\\n                    Log.i(\\\"disturbance\\\",\\\"\\\"+((EventLocQuality) event).getDisturbanceLevel());\\n                    Log.i(\\\"status\\\",\\\"\\\"+((EventLocQuality) event).getLocStatus());\\n                    break;\\n                }\\n            }\\n        }\\n    });\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n#Conclusion #\n\nIn this tutorial, we learned the basics of using the ISKN API:\n- Scan for devices\n- Connect and disconnect from a device\n- Request information\n- Subscribe to event services\n- Receive events and parse them\nA test application was proposed and can be used as a template for custom developments.","excerpt":"","slug":"getting-started-with-iskn-api-on-android","type":"basic","title":"Getting started with ISKN API on Android"}

Getting started with ISKN API on Android


#Introduction # This is a quick start to using the ISKN API on Android studio. At the end of this tutorial, the developer should be capable to create an Android application based on the ISKN API and master the most important concepts about the API architecture and usage. This involves listing the available slates, connecting to a slate, requesting information about the slate as well as subscribing to the ISKN services and decoding slate data. The following tutorial assumes that the developer has already installed Android studio (Android Studio 3.0.1 version - API 21: Android 5.0 (Lollipop) as Minimum SDK version). ## 1.General concepts ### 1.1 Request App permissions To maintain security for the system and users, Android requires apps to request permission before they can use certain system and features. You declare that your app needs a permission by listing the permission in the app manifest and then requesting that the user approve each permission at runtime (on Android 6.0 and higher). Since, the API uses the Bluetooth features, several permissions must be granted. This can be done by using the following entries in the application manifest: [block:code] { "codes": [ { "code": "<uses-permission android:name=\"android.permission.BLUETOOTH\"/>\n<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/>\n<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>\n<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>\n<uses-feature android:name=\"android.hardware.bluetooth_le\" android:required=\"true\"/>\n", "language": "xml" } ] } [/block] ### 1.2 Import API packages To use the ISKN API, you need these import statements: [block:code] { "codes": [ { "code": "import com.iskn.isknApi.*;\nimport com.iskn.isknApi.events.*;\nimport com.iskn.isknApi.bleScanner.*;", "language": "java" } ] } [/block] ### 1.3 The Slate Manager The SlateManager class is the main gateway to communicate with Slates. It provides both scan and communication functionalities through a set of methods such as connect, startScan, subscribe … So it’s required to create a SlateManager instance on the Activity’s onCreate method of the Android app. ### 1.4 The Listener interfaces In order to receive Slate data, the application main class needs to implement two interfaces: Listener interface and BLE_Scan_Listener interface. [block:code] { "codes": [ { "code": "public class MainActivity implements Listener, BLE_Scan_Listener{\n// Do stuff…\n}\n// In this code sample MainActivity class implements both the Listener and BLE_Scan_Listener interfaces\n", "language": "java" } ] } [/block] The reception of data is provided asynchronously via the two Listeners. Each one offers a collection of abstract methods. Unless the class that implements the interfaces is abstract, all the methods of the interfaces need to be defined in the class. - Listener abstract methods: + connectionStatusChanged method It is called whenever the Slate connection status changes (connected or disconnected). + processEvent method It is called whenever an event is sent from the slate (for example, new pen position data has arrived). - BLE_Scan_Listener abstract methods: Implements methods that are called when new slates are discovered, when the discovery fails and when the discovery is finished. + newDeviceFound method. + notify method. + scanFailed method. + scanFinished method. The use of these methods will be explained in the next section. ### 1.5 The scan process The scan for slates is triggered by a call to the **startScan** method of the **SlateManager** class. [block:code] { "codes": [ { "code": "slateManager.startScan(MainActivity.this);\n\n// “MainActivity.this” is an instance of a class that implements the BLE_Scan_Listener", "language": "java" } ] } [/block] Once the scan is launched, the main class that implements the **BLE_Scan_Listener** interface will receive different events through the inherited abstract methods. ## 2.Slates discovery When a new Slate is discovered, the implemented **newDeviceFound** method is called: [block:code] { "codes": [ { "code": "@Override\npublic void newDeviceFound(final BluetoothDevice bluetoothDevice){\n// Do stuff…\n}", "language": "java" } ] } [/block] This methods takes a Bluetooth device as parameter. The discovered Bluetooth device can be added to a list of discovered Slates or we can connect to it directly using its name or address. ### 2.1 Scan status The scan process may have two status states, scan finished or scan failed. When the scan is finished, the scanFinished method is called: [block:code] { "codes": [ { "code": "@Override\npublic void scanFinished() {\n// The scan can be relaunched if necessary\n}", "language": "java" } ] } [/block] And if the scan fails, the scanFailed method is called: [block:code] { "codes": [ { "code": "@Override\npublic void scanFailed(int ) {\n// The user can be notified by displaying a message on the screen \n}", "language": "java" } ] } [/block] ### 2.2 Scan notifications During the scan process the user needs to be notified of some specific issues for example if the Bluetooth is not supported on the used device or if the Bluetooth activation is required. [block:code] { "codes": [ { "code": "public void notify(final BleScanner_Event bleScanner_event, String info){\n// The user can be notified by displaying a message on the screen \n}", "language": "java" } ] } [/block] The main events are: - BLESCANNER_EVENT_BLE_NOT_SUPPORTED: This event is sent if the device does not support Bluetooth. - BLESCANNER_EVENT_ACTIVATION_REQUIRED: This event is sent if the activation of Bluetooth is required. - BLESCANNER_EVENT_BLE_SCAN_STARTED: This event is sent when the Bluetooth scan has started. ### 2.3 The connection process The connection to the Slate is triggered by a call to the connect method of the SlateManager class. #### 2.3.1 Listener registration Before calling the connect method, it is required to register the listener object in order to receive the Slate events. This can be done right after creating the SlateManager object. [block:code] { "codes": [ { "code": "// Create SlateManager object\nslateManager=new SlateManager(this);\n// Register the MainActivity class as a listener\nslateManager.registerListener(this);\n\n// “this” is the listener instance", "language": "java" } ] } [/block] #### 2.3.2 Connection request The connection request can be sent immediately when a device is discovered which means when the **newDeviceFound** method is called. As mentioned before, the developer can either add the discovered Bluetooth device to a list of discovered Slates or connect to it directly using its name or address. [block:code] { "codes": [ { "code": "slateManager.connect(BluetoothDevice device);\n", "language": "java" } ] } [/block] It is important to know that the connect method is overloaded. So it can be used without a Bluetooth device parameter. In this case the app will connect to the first discovered Slate. When the Slate is connected, the **connectionStatusChanged** method is called. [block:code] { "codes": [ { "code": "public void connectionStatusChanged(final boolean connected){\n// in this case, the boolean connected is true\n}", "language": "java" } ] } [/block] If the connection succeeds, the application can subscribe to the Slate services or request individual information like the Slate description or the battery status. #### 2.3.3 Disconnection request Just as the connection, the disconnection is simply executed by calling: [block:code] { "codes": [ { "code": "slateManager.disconnect();", "language": "java" } ] } [/block] Once disconnected, the **connectionStatusChanged** method is called with false as parameter. ### 2.4 The communication workflow Once connected, the Slate waits for application requests. The requests are split into two types: #### 2.4.1 Single requests The Slate replies to those requests instantaneously by sending the requested information. For example, the application may request device information (its name, the size of the capture area...) or battery status. To send a request to the Slate you can use the **request** method of the **SlateManager** class: [block:code] { "codes": [ { "code": "slateManager.request(SlateManager.SingleRequestBlockType.REQ_STATUS);\n // In this example the request block type is REQ_STATUS", "language": "java" } ] } [/block] #### 2.4.2 Subscription requests The application can subscribe to one or more Slate events. There are many events that can be generated by the Slate, such as a pen detection event, that occurs when a pen enters or leaves the Slate view field. When a pen moves, the Slate generates events such as the position, orientation and contact of the pen tip. To send subscription to the Slate you can use the subscribe method of the **SlateManager** class: [block:code] { "codes": [ { "code": "slateManager.subscribe(<One or a combination of AutoBlockType separated by |>)", "language": "java" } ] } [/block] #### 2.4.3 Handle events reception The requests and subscriptions sent to the Slate are managed asynchronously. When a response is sent from the slate, the processEvent method of the listener is called with an Event object: [block:code] { "codes": [ { "code": "public void processEvent(final Event event, int i) {\n\n runOnUiThread(new Runnable() {\n @Override\n public void run() {\n switch(event.getType()){\n case EVT_STATUS: {\n EventStatus evt = (EventStatus) event; \n\t\t // Do stuff…\n break;\n }\n case EVT_DESCRIPTION: {\n EventDescription evt = (EventDescription) event;\n\t\t // Do stuff…\n break;\n }\n case EVT_PEN_3D: {\n EventPen3D evt = (EventPen3D) event;\n\t\t // Do stuff…\n break;\n }\n case EVT_SOFTWARE:{\n EventSoftware evt = (EventSoftware) event;\n\t\t // Do stuff…\n switch(evt.getSoftwareEventType()){\n case SE_OBJECT_IN: \n\t\t\t <User Code Here>\n break;\n case SE_OBJECT_OUT: \n\t\t// Do stuff…\n break;\n }\n break;}}} });\n}", "language": "java" } ] } [/block] In the sample code above the getType method of the Event class is used. It is then possible to cast the event to the right type and then extract the needed information. ## 3.The Android test application In this section, we will focus on creating a simple application that uses the concepts presented above in order to interact with slates. ### 3.1 The application overview When launched, the interface presented in Figure 1 appears. [block:image] { "images": [ { "image": [ "https://files.readme.io/aaffb54-Picture1.png", "Picture1.png", 977, 610, "#2a3a7b" ], "caption": "Figure 1 First view" } ] } [/block] The **START THE SCAN** button is pressed, the tablet starts scanning for Slates. Before scanning, make sure that the slate is powered on and the side led is blinking in blue. When a Slate is discovered, it appears in the devices list. The MAC address of the Slate is displayed as well as its name. [block:image] { "images": [ { "image": [ "https://files.readme.io/ee50d0d-Picture2.png", "Picture2.png", 964, 602, "#2a3a79" ], "caption": "Figure 2 Slate discovered view" } ] } [/block] Select the slate to connect to it. [block:image] { "images": [ { "image": [ "https://files.readme.io/5df8dc8-Picture3.png", "Picture3.png", 972, 606, "#2b3c7b" ], "caption": "Figure 3 Connected slate view" } ] } [/block] Once the Slate is connected, a bunch of information are displayed in the console: Two new buttons appear: **REFRESH** and **DISCONNECT**. The first enables refreshing the slate in case of magnetic disturbances and the second is used to disconnect from it. Finally, the battery status is displayed. Now the slate is ready to send data to the application. In this app, we have subscribed to the Pen3D service which provides the 3 coordinates of the pen tip, the pen surface contact status as well as the angles that describe the pen orientation. The pen tip coordinates are displayed on the screen if the pen is placed in the field of view of the slate. When the pen touches the paper, the pen3D text turns red. [block:image] { "images": [ { "image": [ "https://files.readme.io/f28dc30-Picture4.png", "Picture4.png", 931, 581, "#2b3d7a" ], "caption": "Figure 4 Pen3D position display page" } ] } [/block] When **REFRESH** button is clicked, the slate is refreshed (magnetic disturbances are compensated). Before doing this step, please move away the pen from the Slate surface before pressing this button. To disconnect from the Slate the **DISCONNECT** button can be used. ### 3.2 Creating the application Create an Android application and select **API 21: Android 5.0 (Lollipop)** as a **minimum SDK **version when asked. You can select a higher version if you wish, but the minimum allowed by the ISKN_API is 21. [block:image] { "images": [ { "image": [ "https://files.readme.io/115b2ee-Picture5.png", "Picture5.png", 854, 600, "#63625f" ], "caption": "Figure 5 Target Android Devices" } ] } [/block] Once the activity is created, we have to add the ISKN API module, by selecting File>New>New Module… [block:image] { "images": [ { "image": [ "https://files.readme.io/107dafc-Picture6.png", "Picture6.png", 954, 293, "#e5e8eb" ], "caption": "Figure 6 Add a Module" } ] } [/block] Select import JAR/AAR package and hit next. [block:image] { "images": [ { "image": [ "https://files.readme.io/0cde75d-Picture7.png", "Picture7.png", 908, 670, "#646363" ], "caption": "Figure 7 Import JAR/AAR Package" } ] } [/block] Select the iskn_api-release.aar (release version) or iskn_api-debug.aar (debug version) then hit Finish. [block:image] { "images": [ { "image": [ "https://files.readme.io/f3dd6f9-Picture8.png", "Picture8.png", 968, 689, "#eaeaea" ] } ] } [/block] Make sure the library is listed at the top of your **settings.gradle** file, as shown here for a library named “iskn_api-release”: [block:code] { "codes": [ { "code": "include ':app', ‘:iskn_api-release’", "language": "text" } ] } [/block] Open the app module's **build.gradle** file and add a new line to the dependencies block as shown in the following snippet: [block:code] { "codes": [ { "code": "dependencies {\n compile project(\":iskn_api-release\")\n}", "language": "text" } ] } [/block] Click **Sync Project with Gradle Files.** The project is ready to use the ISKN API. ### 3.3 Import library items As mentioned before, we start by adding the API import statements: [block:code] { "codes": [ { "code": "import com.iskn.isknApi.*;\nimport com.iskn.isknApi.events.*;\nimport com.iskn.isknApi.bleScanner.*;", "language": "java" } ] } [/block] 3.4 Add Listeners implementations to the activity Now add the two needed listeners implementation to the Activity. [block:code] { "codes": [ { "code": "public class MainActivity extends AppCompatActivity implements Listener, BLE_Scan_Listener{\n…\n}", "language": "java" } ] } [/block] You need also to implement the listeners’ methods: [block:code] { "codes": [ { "code": "// ===================================== //\n// Ble_Scan_Listener methods\n// ===================================== //\n\n@Override\npublic void newDeviceFound(final BluetoothDevice bluetoothDevice) {\n// Do stuff…\n}\n\n@Override\npublic void notify(final BleScanner_Event bleScanner_event, String s) {\n// Do stuff…\n}\n\n@Override\npublic void scanFailed(int i) {\n// Do stuff…\n}\n\n@Override\npublic void scanFinished() {\n// Do stuff…\n}\n\n//=====================================//\n// Listener methods\n// ===================================== //\n@Override\npublic void connectionStatusChanged(final boolean connected) {\n // Do stuff…\n}\n\n@Override\npublic void processEvent(final Event event, int i) {\n // Do stuff…\n}", "language": "java" } ] } [/block] ### 3.5 Runtime permission granting As mentioned above, it’s mandatory to list the needed permissions in the app manifest. Furthermore, for SDK versions higher or equal to Marshmallow, it is necessary to ask for the **COARSE_LOCATION** permission in order to be able to use Bluetooth connection. We do this in runtime by using this code: [block:code] { "codes": [ { "code": "// Request permission to access location\nif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);\n}", "language": "java" } ] } [/block] This code should be added in the activity onCreate method before creating the SlateManager object. ### 3.6 Create the Slate Manager Declare a private (or public) member object of type SlateManager without initialising it: [block:code] { "codes": [ { "code": "private SlateManager slateManager;", "language": "java" } ] } [/block] Create the Slate Manager object in the onCreate method of the activity as follows: [block:code] { "codes": [ { "code": "// Create SlateManager object\nslateManager=new SlateManager(this);", "language": "java" } ] } [/block] Now you need to register the activity as the main listener so that we can receive events after the connection to the slate. [block:code] { "codes": [ { "code": "// Register the MainActivity class as a listener\nslateManager.registerListener(this);", "language": "java" } ] } [/block] ### 3.7 Start Scanning Now the scan can be started. The startScan method in the onClick event listener of the **START SCAN** button: [block:code] { "codes": [ { "code": "btnScan.setOnClickListener(new View.OnClickListener() {\n @Override\n public void onClick(View v) {\n llConnection.setVisibility(View.GONE);\n // Rest the list content\n items.clear();\n adapter.notifyDataSetChanged();\n // Start scanning for devices\n slateManager.stopScan();\n slateManager.startScan(MainActivity.this);\n appendInfo(\"Scanning...\\n\");\n }\n});", "language": "java" } ] } [/block] Here we gave the **startScan** method the current activity as a parameter so it receives all the scan events. ### 3.8 New device found event Now whenever a new Slate is found, add it to the list of the discovered Slates: [block:code] { "codes": [ { "code": "@Override\npublic void newDeviceFound(final BluetoothDevice bluetoothDevice) {\n runOnUiThread(new Runnable() {\n @Override\n public void run() {\n final BluetoothDevice p_device=bluetoothDevice;\n appendInfo( \"Device \"+p_device.getName()+\" found\\n\");\n if(p_device.getName()!=null) {\n items.add(p_device.getName()+\" : \"+p_device.getAddress());\n }\n else\n {\n items.add(\"No Name : \"+p_device.getAddress());\n }\n adapter.notifyDataSetChanged();\n } });\n}", "language": "java" } ] } [/block] ### 3.9 Connect to the selected Slate When the user select a Slate among the list, the scan process is stopped and a connection request is sent via the connect method of the SlateManager object. [block:code] { "codes": [ { "code": "// When a device is selected, we connect to it\nlstDevices.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n @Override\n public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n // Stop scanning\n slateManager.stopScan();\n\n // Connect to the selected device\n slateManager.connect(slateManager.getDeviceByIndex(position));\n btnScan.setVisibility(GONE);\n appendInfo(\"Connecting...\\n\");\n }\n});", "language": "java" } ] } [/block] Notice that we fetch the device by its index in the list. If connection succeeded, the method connectionStatusChanged is called with the connected parameter set to true. ### 3.10 Request information and subscribe to events In the connectionStatusChanged method, we can request information (Slate description as well as its status) and subscribe to useful services: [block:code] { "codes": [ { "code": "@Override\npublic void connectionStatusChanged(final boolean connected) {\n runOnUiThread(new Runnable() {\n @Override\n public void run() {\n if (connected) {\n slateManager.request(SlateManager.SingleRequestBlockType.REQ_DESCRIPTION);\n slateManager.request(SlateManager.SingleRequestBlockType.REQ_STATUS);\n\n slateManager.subscribe(SlateManager.AutoBlockType.AUTO_STATUS.type() |\n SlateManager.AutoBlockType.AUTO_PEN_3D.type() |\n SlateManager.AutoBlockType.AUTO_HARDWARE_EVENTS.type() |\n SlateManager.AutoBlockType.AUTO_SOFTWARE_EVENTS.type());\n\n device = slateManager.getDevice();\n llConnection.setVisibility(View.VISIBLE);\n } else {\n txtInfos.setText(\"\");\n appendInfo(txtInfos.getText() + \"Disconnected from \" + device.getDeviceName() + \"\\n\");\n llConnection.setVisibility(GONE);\n btnScan.setVisibility(VISIBLE);\n }\n }\n });\n}", "language": "java" } ] } [/block] Notice that we use the Activity’s runOnUiThread method. In fact the ISKN API methods are executed on a worker thread. But, when the time comes to update the UI we must “return” to the Main Thread, as only he’s allowed to touch and update the application UI. A common way to achieve this is to call the Activity’s runOnUiThread method: [block:code] { "codes": [ { "code": "runOnUiThread(new Runnable() {\n void run() {\n // Do stuff…\n }\n});", "language": "java" } ] } [/block] ### 3.11 Receive and process events Once we are subscribed to events, any time one of these events occur, the processEvent method is called. Here is an example of parsing and using the received information. [block:code] { "codes": [ { "code": "@Override\npublic void processEvent(final Event event, int i) {\n // All ISNK related handlers need to run their code on tne main thread if they touch the ui\n // since these methods are called from another thread\n runOnUiThread(new Runnable() {\n @Override\n public void run() {\n switch(event.getType()){\n case EVT_STATUS: {\n EventStatus evt = (EventStatus) event;\n if(evt.getBattery()<10)\n txtBattery.setTextColor(Color.RED);\n else\n if(evt.getBattery()<70)\n txtBattery.setTextColor(Color.rgb(255,165,0));\n else\n txtBattery.setTextColor(Color.GREEN);\n txtBattery.setText(\"Battery :\"+evt.getBattery()+\"% \"+(evt.isBatteryInCharge()==1?\"Charging\":\"\"));\n appendInfo( \"Battery :\" + evt.getBattery()+\"%\\n\");\n appendInfo( \"Battery is charging ? \" + (evt.isBatteryInCharge()==1?\"Yes\":\"NO\")+\"\\n\");\n break;\n }\n case EVT_DESCRIPTION: {\n EventDescription evt = (EventDescription) event;\n Rect activeZone=evt.getActiveZone();\n Size SlateSize=evt.getSlateSize();\n String name=evt.getDeviceName();\n appendInfo( \"Connected to \" + name+\"\\n\");\n appendInfo( \"Firmware version :\" + evt.getFirmwareVersion()+\"\\n\");\n appendInfo( \"Slate Size (mm): \" +\" width : \"+SlateSize.getWidth()+\" height : \"+SlateSize.getHeight()+\"\\n\");\n appendInfo( \"Active Zone (mm): \" +\" left : \"+activeZone.getLeft()+\" top : \"+activeZone.getTop()+\" width : \"+activeZone.getWidth()+\" height : \"+activeZone.getHeight()+\"\\n\");\n break;\n }\n case EVT_PEN_3D: {\n EventPen3D evt = (EventPen3D) event;\n Vector3D vec=evt.getPosition();\n if(evt.Touch())\n txtPos.setTextColor(Color.RED);\n else\n txtPos.setTextColor(Color.GREEN);\n txtPos.setText(\"Pen 3D : \" + vec.getPosX() +\",\"+vec.getPosY()+vec.getPosZ()+\"\\n\");\n break;\n }\n case EVT_SOFTWARE:{\n EventSoftware evt = (EventSoftware) event;\n switch(evt.getSoftwareEventType()){\n case SE_OBJECT_IN:\n appendInfo( \"Pen \"+ evt.getObjectID() +\" in\\n\");\n break;\n case SE_OBJECT_OUT:\n appendInfo( \"Pen \"+ evt.getObjectID() +\" out\\n\");\n break;\n }\n break;\n }\n case EVT_HARDWARE: {\n EventHardware evt = (EventHardware) event;\n switch (evt.getHardwareEventType()){\n case HE_BUTTON1_PRESSED:\n appendInfo( \"Button 1 pressed\\n\");\n break;\n case HE_BUTTON2_PRESSED:\n appendInfo( \"Button 2 pressed\\n\");\n break;\n case HE_BUTTON1_LONGPRESS:\n appendInfo( \"Button 1 long pressed\\n\");\n break;\n case HE_BUTTON2_LONGPRESS:\n appendInfo( \"Button 2 long pressed\\n\");\n break;\n case HE_UNKNOWN:\n appendInfo( \"Unknown hardware event\\n\");\n break;\n case HE_REFRESH_DONE:\n appendInfo( \"Slate refresh is done\\n\");\n break;\n default:\n appendInfo( \"Unknown hardware evnt \\n\");\n break;\n }\n break;\n }\n case EVT_LOC_QUALITY:{\n EventLocQuality evt=(EventLocQuality)event;\n Log.i(\"disturbance\",\"\"+((EventLocQuality) event).getDisturbanceLevel());\n Log.i(\"status\",\"\"+((EventLocQuality) event).getLocStatus());\n break;\n }\n }\n }\n });\n}", "language": "java" } ] } [/block] #Conclusion # In this tutorial, we learned the basics of using the ISKN API: - Scan for devices - Connect and disconnect from a device - Request information - Subscribe to event services - Receive events and parse them A test application was proposed and can be used as a template for custom developments.