2 * //******************************************************************
4 * // Copyright 2015 Intel Corporation.
6 * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
8 * // Licensed under the Apache License, Version 2.0 (the "License");
9 * // you may not use this file except in compliance with the License.
10 * // You may obtain a copy of the License at
12 * // http://www.apache.org/licenses/LICENSE-2.0
14 * // Unless required by applicable law or agreed to in writing, software
15 * // distributed under the License is distributed on an "AS IS" BASIS,
16 * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * // See the License for the specific language governing permissions and
18 * // limitations under the License.
20 * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
22 package org.iotivity.base.examples;
24 import android.app.Activity;
25 import android.content.Context;
26 import android.os.Bundle;
27 import android.text.method.ScrollingMovementMethod;
28 import android.util.Log;
29 import android.view.View;
30 import android.widget.Button;
31 import android.widget.ScrollView;
32 import android.widget.TextView;
34 import org.iotivity.base.ErrorCode;
35 import org.iotivity.base.ModeType;
36 import org.iotivity.base.ObserveType;
37 import org.iotivity.base.OcConnectivityType;
38 import org.iotivity.base.OcException;
39 import org.iotivity.base.OcHeaderOption;
40 import org.iotivity.base.OcPlatform;
41 import org.iotivity.base.OcRepresentation;
42 import org.iotivity.base.OcResource;
43 import org.iotivity.base.OcResourceIdentifier;
44 import org.iotivity.base.PlatformConfig;
45 import org.iotivity.base.QualityOfService;
46 import org.iotivity.base.ServiceType;
48 import java.util.EnumSet;
49 import java.util.HashMap;
50 import java.util.List;
56 * SimpleClient is a sample client app which should be started after the simpleServer is started.
57 * It finds resources advertised by the server and calls different operations on it (GET, PUT,
58 * POST, DELETE and OBSERVE).
60 public class SimpleClient extends Activity implements
61 OcPlatform.OnResourceFoundListener,
62 OcResource.OnGetListener,
63 OcResource.OnPutListener,
64 OcResource.OnPostListener,
65 OcResource.OnObserveListener {
67 private Map<OcResourceIdentifier, OcResource> mFoundResources = new HashMap<>();
68 private OcResource mFoundLightResource = null;
69 //local representation of a server's light resource
70 private Light mLight = new Light();
73 * A local method to configure and initialize platform, and then search for the light resources.
75 private void startSimpleClient() {
76 Context context = this;
78 PlatformConfig platformConfig = new PlatformConfig(
82 "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
83 0, // Uses randomly available port
87 msg("Configuring platform.");
88 OcPlatform.Configure(platformConfig);
91 msg("Finding all resources of type \"core.light\".");
92 String requestUri = OcPlatform.WELL_KNOWN_QUERY + "?rt=core.light";
93 OcPlatform.findResource("",
95 EnumSet.of(OcConnectivityType.CT_DEFAULT),
100 /*Find resource is done twice so that we discover the original resources a second time.
101 These resources will have the same uniqueidentifier (yet be different objects),
102 so that we can verify/show the duplicate-checking code in foundResource(above);
104 msg("Finding all resources of type \"core.light\" for the second time");
105 OcPlatform.findResource("",
107 EnumSet.of(OcConnectivityType.CT_DEFAULT),
111 } catch (OcException e) {
112 Log.e(TAG, e.toString());
113 msg("Failed to invoke find resource API");
120 * An event handler to be executed whenever a "findResource" request completes successfully
122 * @param ocResource found resource
125 public synchronized void onResourceFound(OcResource ocResource) {
126 if (null == ocResource) {
127 msg("Found resource is invalid");
131 if (mFoundResources.containsKey(ocResource.getUniqueIdentifier())) {
132 msg("Found a previously seen resource again!");
134 msg("Found resource for the first time on server with ID: " + ocResource.getServerId());
135 mFoundResources.put(ocResource.getUniqueIdentifier(), ocResource);
138 if (null != mFoundLightResource) {
139 msg("Found another resource, ignoring");
142 // Get the resource URI
143 String resourceUri = ocResource.getUri();
144 // Get the resource host address
145 String hostAddress = ocResource.getHost();
146 msg("\tURI of the resource: " + resourceUri);
147 msg("\tHost address of the resource: " + hostAddress);
148 // Get the resource types
149 msg("\tList of resource types: ");
150 for (String resourceType : ocResource.getResourceTypes()) {
151 msg("\t\t" + resourceType);
153 msg("\tList of resource interfaces:");
154 for (String resourceInterface : ocResource.getResourceInterfaces()) {
155 msg("\t\t" + resourceInterface);
157 msg("\tList of resource connectivity types:");
158 for (OcConnectivityType connectivityType : ocResource.getConnectivityTypeSet()) {
159 msg("\t\t" + connectivityType);
163 //In this example we are only interested in the light resources
164 if (resourceUri.equals("/a/light")) {
165 //Assign resource reference to a global variable to keep it from being
166 //destroyed by the GC when it is out of scope.
167 mFoundLightResource = ocResource;
169 // Call a local method which will internally invoke "get" API on the foundLightResource
170 getLightResourceRepresentation();
175 * Local method to get representation of a found light resource
177 private void getLightResourceRepresentation() {
178 msg("Getting Light Representation...");
180 Map<String, String> queryParams = new HashMap<>();
182 // Invoke resource's "get" API with a OcResource.OnGetListener event
183 // listener implementation
185 mFoundLightResource.get(queryParams, this);
186 } catch (OcException e) {
187 Log.e(TAG, e.toString());
188 msg("Error occurred while invoking \"get\" API");
193 * An event handler to be executed whenever a "get" request completes successfully
195 * @param list list of the header options
196 * @param ocRepresentation representation of a resource
199 public synchronized void onGetCompleted(List<OcHeaderOption> list,
200 OcRepresentation ocRepresentation) {
201 msg("GET request was successful");
202 msg("Resource URI: " + ocRepresentation.getUri());
205 //Read attribute values into local representation of a light
206 mLight.setOcRepresentation(ocRepresentation);
207 } catch (OcException e) {
208 Log.e(TAG, e.toString());
209 msg("Failed to read the attributes of a light resource");
211 msg("Light attributes: ");
212 msg(mLight.toString());
215 //Call a local method which will internally invoke put API on the foundLightResource
216 putLightRepresentation();
220 * An event handler to be executed whenever a "get" request fails
222 * @param throwable exception
225 public synchronized void onGetFailed(Throwable throwable) {
226 if (throwable instanceof OcException) {
227 OcException ocEx = (OcException) throwable;
228 Log.e(TAG, ocEx.toString());
229 ErrorCode errCode = ocEx.getErrorCode();
230 //do something based on errorCode
231 msg("Error code: " + errCode);
233 msg("Failed to get representation of a found light resource");
237 * Local method to put a different state for this light resource
239 private void putLightRepresentation() {
241 mLight.setState(true);
244 msg("Putting light representation...");
245 OcRepresentation representation = null;
247 representation = mLight.getOcRepresentation();
248 } catch (OcException e) {
249 Log.e(TAG, e.toString());
250 msg("Failed to get OcRepresentation from a light");
253 Map<String, String> queryParams = new HashMap<>();
257 // Invoke resource's "put" API with a new representation, query parameters and
258 // OcResource.OnPutListener event listener implementation
259 mFoundLightResource.put(representation, queryParams, this);
260 } catch (OcException e) {
261 Log.e(TAG, e.toString());
262 msg("Error occurred while invoking \"put\" API");
267 * An event handler to be executed whenever a "put" request completes successfully
269 * @param list list of the header options
270 * @param ocRepresentation representation of a resource
273 public synchronized void onPutCompleted(List<OcHeaderOption> list, OcRepresentation ocRepresentation) {
274 msg("PUT request was successful");
276 mLight.setOcRepresentation(ocRepresentation);
277 } catch (OcException e) {
278 Log.e(TAG, e.toString());
279 msg("Failed to create Light representation");
281 msg("Light attributes: ");
282 msg(mLight.toString());
285 //Call a local method which will internally invoke post API on the foundLightResource
286 postLightRepresentation();
290 * An event handler to be executed whenever a "put" request fails
292 * @param throwable exception
295 public synchronized void onPutFailed(Throwable throwable) {
296 if (throwable instanceof OcException) {
297 OcException ocEx = (OcException) throwable;
298 Log.e(TAG, ocEx.toString());
299 ErrorCode errCode = ocEx.getErrorCode();
300 //do something based on errorCode
301 msg("Error code: " + errCode);
303 msg("Failed to \"put\" a new representation");
307 * Local method to post a different state for this light resource
309 private void postLightRepresentation() {
311 mLight.setState(false);
312 mLight.setPower(105);
314 msg("Posting light representation...");
315 OcRepresentation representation = null;
317 representation = mLight.getOcRepresentation();
318 } catch (OcException e) {
319 Log.e(TAG, e.toString());
320 msg("Failed to get OcRepresentation from a light");
323 Map<String, String> queryParams = new HashMap<>();
326 // Invoke resource's "post" API with a new representation, query parameters and
327 // OcResource.OnPostListener event listener implementation
328 mFoundLightResource.post(representation, queryParams, this);
329 } catch (OcException e) {
330 Log.e(TAG, e.toString());
331 msg("Error occurred while invoking \"post\" API");
336 * An event handler to be executed whenever a "post" request completes successfully
338 * @param list list of the header options
339 * @param ocRepresentation representation of a resource
342 public synchronized void onPostCompleted(List<OcHeaderOption> list,
343 OcRepresentation ocRepresentation) {
344 msg("POST request was successful");
346 if (ocRepresentation.hasAttribute(OcResource.CREATED_URI_KEY)) {
347 msg("\tUri of the created resource: " +
348 ocRepresentation.getValue(OcResource.CREATED_URI_KEY));
350 mLight.setOcRepresentation(ocRepresentation);
351 msg(mLight.toString());
353 } catch (OcException e) {
354 Log.e(TAG, e.toString());
358 mLight.setState(true);
360 msg("Posting again light representation...");
361 OcRepresentation representation2 = null;
363 representation2 = mLight.getOcRepresentation();
364 } catch (OcException e) {
365 Log.e(TAG, e.toString());
366 msg("Failed to get OcRepresentation from a light");
369 Map<String, String> queryParams = new HashMap<>();
371 // Invoke resource's "post" API with a new representation, query parameters and
372 // OcResource.OnPostListener event listener implementation
373 mFoundLightResource.post(representation2, queryParams, onPostListener2);
374 } catch (OcException e) {
375 Log.e(TAG, e.toString());
376 msg("Error occurred while invoking \"post\" API");
381 * An event handler to be executed whenever a "post" request fails
383 * @param throwable exception
386 public synchronized void onPostFailed(Throwable throwable) {
387 if (throwable instanceof OcException) {
388 OcException ocEx = (OcException) throwable;
389 Log.e(TAG, ocEx.toString());
390 ErrorCode errCode = ocEx.getErrorCode();
391 //do something based on errorCode
392 msg("Error code: " + errCode);
394 msg("Failed to \"post\" a new representation");
398 * Declare and implement a second OcResource.OnPostListener
400 OcResource.OnPostListener onPostListener2 = new OcResource.OnPostListener() {
402 * An event handler to be executed whenever a "post" request completes successfully
403 * @param list list of the header options
404 * @param ocRepresentation representation of a resource
407 public synchronized void onPostCompleted(List<OcHeaderOption> list,
408 OcRepresentation ocRepresentation) {
409 msg("Second POST request was successful");
411 if (ocRepresentation.hasAttribute(OcResource.CREATED_URI_KEY)) {
412 msg("\tUri of the created resource: " +
413 ocRepresentation.getValue(OcResource.CREATED_URI_KEY));
415 mLight.setOcRepresentation(ocRepresentation);
416 msg(mLight.toString());
418 } catch (OcException e) {
419 Log.e(TAG, e.toString());
422 //Call a local method which will internally invoke observe API on the foundLightResource
423 observeFoundLightResource();
427 * An event handler to be executed whenever a "post" request fails
429 * @param throwable exception
432 public synchronized void onPostFailed(Throwable throwable) {
433 if (throwable instanceof OcException) {
434 OcException ocEx = (OcException) throwable;
435 Log.e(TAG, ocEx.toString());
436 ErrorCode errCode = ocEx.getErrorCode();
437 //do something based on errorCode
438 msg("Error code: " + errCode);
440 msg("Failed to \"post\" a new representation");
445 * Local method to start observing this light resource
447 private void observeFoundLightResource() {
450 // Invoke resource's "observe" API with a observe type, query parameters and
451 // OcResource.OnObserveListener event listener implementation
452 mFoundLightResource.observe(ObserveType.OBSERVE, new HashMap<String, String>(), this);
453 } catch (OcException e) {
454 Log.e(TAG, e.toString());
455 msg("Error occurred while invoking \"observe\" API");
459 // holds current number of observations
460 private static int mObserveCount = 0;
463 * An event handler to be executed whenever a "post" request completes successfully
465 * @param list list of the header options
466 * @param ocRepresentation representation of a resource
467 * @param sequenceNumber sequence number
470 public synchronized void onObserveCompleted(List<OcHeaderOption> list,
471 OcRepresentation ocRepresentation,
472 int sequenceNumber) {
473 if (OcResource.OnObserveListener.REGISTER == sequenceNumber) {
474 msg("Observe registration action is successful:");
475 } else if (OcResource.OnObserveListener.DEREGISTER == sequenceNumber) {
476 msg("Observe De-registration action is successful");
477 } else if (OcResource.OnObserveListener.NO_OPTION == sequenceNumber) {
478 msg("Observe registration or de-registration action is failed");
481 msg("OBSERVE Result:");
482 msg("\tSequenceNumber:" + sequenceNumber);
484 mLight.setOcRepresentation(ocRepresentation);
485 } catch (OcException e) {
486 Log.e(TAG, e.toString());
487 msg("Failed to get the attribute values");
489 msg(mLight.toString());
491 if ((++mObserveCount) == 11) {
492 msg("Cancelling Observe...");
494 mFoundLightResource.cancelObserve();
495 } catch (OcException e) {
496 Log.e(TAG, e.toString());
497 msg("Error occurred while invoking \"cancelObserve\" API");
501 //prepare for the next restart of the SimpleClient
508 * An event handler to be executed whenever a "observe" request fails
510 * @param throwable exception
513 public synchronized void onObserveFailed(Throwable throwable) {
514 if (throwable instanceof OcException) {
515 OcException ocEx = (OcException) throwable;
516 Log.e(TAG, ocEx.toString());
517 ErrorCode errCode = ocEx.getErrorCode();
518 //do something based on errorCode
519 msg("Error code: " + errCode);
521 msg("Observation of the found light resource has failed");
524 //******************************************************************************
525 // End of the OIC specific code
526 //******************************************************************************
528 private final static String TAG = SimpleClient.class.getSimpleName();
529 private TextView mConsoleTextView;
530 private ScrollView mScrollView;
532 protected void onCreate(Bundle savedInstanceState) {
533 super.onCreate(savedInstanceState);
534 setContentView(R.layout.activity_simple_client);
536 mConsoleTextView = (TextView) findViewById(R.id.consoleTextView);
537 mConsoleTextView.setMovementMethod(new ScrollingMovementMethod());
538 mScrollView = (ScrollView) findViewById(R.id.scrollView);
539 mScrollView.fullScroll(View.FOCUS_DOWN);
540 final Button button = (Button) findViewById(R.id.button);
542 if (null == savedInstanceState) {
543 button.setOnClickListener(new View.OnClickListener() {
545 public void onClick(View v) {
546 button.setText("Re-start");
547 button.setEnabled(false);
548 new Thread(new Runnable() {
556 String consoleOutput = savedInstanceState.getString("consoleOutputString");
557 mConsoleTextView.setText(consoleOutput);
562 protected void onSaveInstanceState(Bundle outState) {
563 super.onSaveInstanceState(outState);
564 outState.putString("consoleOutputString", mConsoleTextView.getText().toString());
568 protected void onRestoreInstanceState(Bundle savedInstanceState) {
569 super.onRestoreInstanceState(savedInstanceState);
571 String consoleOutput = savedInstanceState.getString("consoleOutputString");
572 mConsoleTextView.setText(consoleOutput);
575 private void enableStartButton() {
576 runOnUiThread(new Runnable() {
578 Button button = (Button) findViewById(R.id.button);
579 button.setEnabled(true);
584 private void sleep(int seconds) {
586 Thread.sleep(seconds * 1000);
587 } catch (InterruptedException e) {
589 Log.e(TAG, e.toString());
593 private void msg(final String text) {
594 runOnUiThread(new Runnable() {
596 mConsoleTextView.append("\n");
597 mConsoleTextView.append(text);
598 mScrollView.fullScroll(View.FOCUS_DOWN);
604 private void printLine() {
605 msg("------------------------------------------------------------------------");
608 private synchronized void resetGlobals() {
609 mFoundLightResource = null;
610 mFoundResources.clear();
611 mLight = new Light();