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.content.Intent;
27 import android.nfc.NfcAdapter;
28 import android.os.Bundle;
29 import android.text.method.ScrollingMovementMethod;
30 import android.util.Log;
31 import android.view.View;
32 import android.widget.Button;
33 import android.widget.ScrollView;
34 import android.widget.TextView;
36 import org.iotivity.base.ErrorCode;
37 import org.iotivity.base.ModeType;
38 import org.iotivity.base.ObserveType;
39 import org.iotivity.base.OcConnectivityType;
40 import org.iotivity.base.OcException;
41 import org.iotivity.base.OcHeaderOption;
42 import org.iotivity.base.OcPlatform;
43 import org.iotivity.base.OcRepresentation;
44 import org.iotivity.base.OcResource;
45 import org.iotivity.base.OcResourceIdentifier;
46 import org.iotivity.base.PlatformConfig;
47 import org.iotivity.base.QualityOfService;
48 import org.iotivity.base.ServiceType;
50 import java.util.EnumSet;
51 import java.util.HashMap;
52 import java.util.List;
58 * SimpleClient is a sample client app which should be started after the simpleServer is started.
59 * It finds resources advertised by the server and calls different operations on it (GET, PUT,
60 * POST, DELETE and OBSERVE).
62 public class SimpleClient extends Activity implements
63 OcPlatform.OnResourceFoundListener,
64 OcResource.OnGetListener,
65 OcResource.OnPutListener,
66 OcResource.OnPostListener,
67 OcResource.OnObserveListener {
69 private Map<OcResourceIdentifier, OcResource> mFoundResources = new HashMap<>();
70 private OcResource mFoundLightResource = null;
71 //local representation of a server's light resource
72 private Light mLight = new Light();
75 * A local method to configure and initialize platform, and then search for the light resources.
77 private void startSimpleClient() {
78 Context context = this;
80 PlatformConfig platformConfig = new PlatformConfig(
85 "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
86 0, // Uses randomly available port
89 msg("Configuring platform.");
90 OcPlatform.Configure(platformConfig);
93 msg("Finding all resources of type \"core.light\".");
94 String requestUri = OcPlatform.WELL_KNOWN_QUERY + "?rt=core.light";
95 OcPlatform.findResource("",
97 EnumSet.of(OcConnectivityType.CT_DEFAULT),
102 /*Find resource is done twice so that we discover the original resources a second time.
103 These resources will have the same uniqueidentifier (yet be different objects),
104 so that we can verify/show the duplicate-checking code in foundResource(above);
106 msg("Finding all resources of type \"core.light\" for the second time");
107 OcPlatform.findResource("",
109 EnumSet.of(OcConnectivityType.CT_DEFAULT),
113 } catch (OcException e) {
114 Log.e(TAG, e.toString());
115 msg("Failed to invoke find resource API");
122 * An event handler to be executed whenever a "findResource" request completes successfully
124 * @param ocResource found resource
127 public synchronized void onResourceFound(OcResource ocResource) {
128 if (null == ocResource) {
129 msg("Found resource is invalid");
133 if (mFoundResources.containsKey(ocResource.getUniqueIdentifier())) {
134 msg("Found a previously seen resource again!");
136 msg("Found resource for the first time on server with ID: " + ocResource.getServerId());
137 mFoundResources.put(ocResource.getUniqueIdentifier(), ocResource);
140 if (null != mFoundLightResource) {
141 msg("Found another resource, ignoring");
144 // Get the resource URI
145 String resourceUri = ocResource.getUri();
146 // Get the resource host address
147 String hostAddress = ocResource.getHost();
148 msg("\tURI of the resource: " + resourceUri);
149 msg("\tHost address of the resource: " + hostAddress);
150 // Get the resource types
151 msg("\tList of resource types: ");
152 for (String resourceType : ocResource.getResourceTypes()) {
153 msg("\t\t" + resourceType);
155 msg("\tList of resource interfaces:");
156 for (String resourceInterface : ocResource.getResourceInterfaces()) {
157 msg("\t\t" + resourceInterface);
159 msg("\tList of resource connectivity types:");
160 for (OcConnectivityType connectivityType : ocResource.getConnectivityTypeSet()) {
161 msg("\t\t" + connectivityType);
165 //In this example we are only interested in the light resources
166 if (resourceUri.equals("/a/light")) {
167 //Assign resource reference to a global variable to keep it from being
168 //destroyed by the GC when it is out of scope.
169 mFoundLightResource = ocResource;
171 // Call a local method which will internally invoke "get" API on the foundLightResource
172 getLightResourceRepresentation();
177 * Local method to get representation of a found light resource
179 private void getLightResourceRepresentation() {
180 msg("Getting Light Representation...");
182 Map<String, String> queryParams = new HashMap<>();
184 // Invoke resource's "get" API with a OcResource.OnGetListener event
185 // listener implementation
187 mFoundLightResource.get(queryParams, this);
188 } catch (OcException e) {
189 Log.e(TAG, e.toString());
190 msg("Error occurred while invoking \"get\" API");
195 * An event handler to be executed whenever a "get" request completes successfully
197 * @param list list of the header options
198 * @param ocRepresentation representation of a resource
201 public synchronized void onGetCompleted(List<OcHeaderOption> list,
202 OcRepresentation ocRepresentation) {
203 msg("GET request was successful");
204 msg("Resource URI: " + ocRepresentation.getUri());
207 //Read attribute values into local representation of a light
208 mLight.setOcRepresentation(ocRepresentation);
209 } catch (OcException e) {
210 Log.e(TAG, e.toString());
211 msg("Failed to read the attributes of a light resource");
213 msg("Light attributes: ");
214 msg(mLight.toString());
217 //Call a local method which will internally invoke put API on the foundLightResource
218 putLightRepresentation();
222 * An event handler to be executed whenever a "get" request fails
224 * @param throwable exception
227 public synchronized void onGetFailed(Throwable throwable) {
228 if (throwable instanceof OcException) {
229 OcException ocEx = (OcException) throwable;
230 Log.e(TAG, ocEx.toString());
231 ErrorCode errCode = ocEx.getErrorCode();
232 //do something based on errorCode
233 msg("Error code: " + errCode);
235 msg("Failed to get representation of a found light resource");
239 * Local method to put a different state for this light resource
241 private void putLightRepresentation() {
243 mLight.setState(true);
246 msg("Putting light representation...");
247 OcRepresentation representation = null;
249 representation = mLight.getOcRepresentation();
250 } catch (OcException e) {
251 Log.e(TAG, e.toString());
252 msg("Failed to get OcRepresentation from a light");
255 Map<String, String> queryParams = new HashMap<>();
259 // Invoke resource's "put" API with a new representation, query parameters and
260 // OcResource.OnPutListener event listener implementation
261 mFoundLightResource.put(representation, queryParams, this);
262 } catch (OcException e) {
263 Log.e(TAG, e.toString());
264 msg("Error occurred while invoking \"put\" API");
269 * An event handler to be executed whenever a "put" request completes successfully
271 * @param list list of the header options
272 * @param ocRepresentation representation of a resource
275 public synchronized void onPutCompleted(List<OcHeaderOption> list, OcRepresentation ocRepresentation) {
276 msg("PUT request was successful");
278 mLight.setOcRepresentation(ocRepresentation);
279 } catch (OcException e) {
280 Log.e(TAG, e.toString());
281 msg("Failed to create Light representation");
283 msg("Light attributes: ");
284 msg(mLight.toString());
287 //Call a local method which will internally invoke post API on the foundLightResource
288 postLightRepresentation();
292 * An event handler to be executed whenever a "put" request fails
294 * @param throwable exception
297 public synchronized void onPutFailed(Throwable throwable) {
298 if (throwable instanceof OcException) {
299 OcException ocEx = (OcException) throwable;
300 Log.e(TAG, ocEx.toString());
301 ErrorCode errCode = ocEx.getErrorCode();
302 //do something based on errorCode
303 msg("Error code: " + errCode);
305 msg("Failed to \"put\" a new representation");
309 * Local method to post a different state for this light resource
311 private void postLightRepresentation() {
313 mLight.setState(false);
314 mLight.setPower(105);
316 msg("Posting light representation...");
317 OcRepresentation representation = null;
319 representation = mLight.getOcRepresentation();
320 } catch (OcException e) {
321 Log.e(TAG, e.toString());
322 msg("Failed to get OcRepresentation from a light");
325 Map<String, String> queryParams = new HashMap<>();
328 // Invoke resource's "post" API with a new representation, query parameters and
329 // OcResource.OnPostListener event listener implementation
330 mFoundLightResource.post(representation, queryParams, this);
331 } catch (OcException e) {
332 Log.e(TAG, e.toString());
333 msg("Error occurred while invoking \"post\" API");
338 * An event handler to be executed whenever a "post" request completes successfully
340 * @param list list of the header options
341 * @param ocRepresentation representation of a resource
344 public synchronized void onPostCompleted(List<OcHeaderOption> list,
345 OcRepresentation ocRepresentation) {
346 msg("POST request was successful");
348 if (ocRepresentation.hasAttribute(OcResource.CREATED_URI_KEY)) {
349 msg("\tUri of the created resource: " +
350 ocRepresentation.getValue(OcResource.CREATED_URI_KEY));
352 mLight.setOcRepresentation(ocRepresentation);
353 msg(mLight.toString());
355 } catch (OcException e) {
356 Log.e(TAG, e.toString());
360 mLight.setState(true);
362 msg("Posting again light representation...");
363 OcRepresentation representation2 = null;
365 representation2 = mLight.getOcRepresentation();
366 } catch (OcException e) {
367 Log.e(TAG, e.toString());
368 msg("Failed to get OcRepresentation from a light");
371 Map<String, String> queryParams = new HashMap<>();
373 // Invoke resource's "post" API with a new representation, query parameters and
374 // OcResource.OnPostListener event listener implementation
375 mFoundLightResource.post(representation2, queryParams, onPostListener2);
376 } catch (OcException e) {
377 Log.e(TAG, e.toString());
378 msg("Error occurred while invoking \"post\" API");
383 * An event handler to be executed whenever a "post" request fails
385 * @param throwable exception
388 public synchronized void onPostFailed(Throwable throwable) {
389 if (throwable instanceof OcException) {
390 OcException ocEx = (OcException) throwable;
391 Log.e(TAG, ocEx.toString());
392 ErrorCode errCode = ocEx.getErrorCode();
393 //do something based on errorCode
394 msg("Error code: " + errCode);
396 msg("Failed to \"post\" a new representation");
400 * Declare and implement a second OcResource.OnPostListener
402 OcResource.OnPostListener onPostListener2 = new OcResource.OnPostListener() {
404 * An event handler to be executed whenever a "post" request completes successfully
405 * @param list list of the header options
406 * @param ocRepresentation representation of a resource
409 public synchronized void onPostCompleted(List<OcHeaderOption> list,
410 OcRepresentation ocRepresentation) {
411 msg("Second POST request was successful");
413 if (ocRepresentation.hasAttribute(OcResource.CREATED_URI_KEY)) {
414 msg("\tUri of the created resource: " +
415 ocRepresentation.getValue(OcResource.CREATED_URI_KEY));
417 mLight.setOcRepresentation(ocRepresentation);
418 msg(mLight.toString());
420 } catch (OcException e) {
421 Log.e(TAG, e.toString());
424 //Call a local method which will internally invoke observe API on the foundLightResource
425 observeFoundLightResource();
429 * An event handler to be executed whenever a "post" request fails
431 * @param throwable exception
434 public synchronized void onPostFailed(Throwable throwable) {
435 if (throwable instanceof OcException) {
436 OcException ocEx = (OcException) throwable;
437 Log.e(TAG, ocEx.toString());
438 ErrorCode errCode = ocEx.getErrorCode();
439 //do something based on errorCode
440 msg("Error code: " + errCode);
442 msg("Failed to \"post\" a new representation");
447 * Local method to start observing this light resource
449 private void observeFoundLightResource() {
452 // Invoke resource's "observe" API with a observe type, query parameters and
453 // OcResource.OnObserveListener event listener implementation
454 mFoundLightResource.observe(ObserveType.OBSERVE, new HashMap<String, String>(), this);
455 } catch (OcException e) {
456 Log.e(TAG, e.toString());
457 msg("Error occurred while invoking \"observe\" API");
461 // holds current number of observations
462 private static int mObserveCount = 0;
465 * An event handler to be executed whenever a "post" request completes successfully
467 * @param list list of the header options
468 * @param ocRepresentation representation of a resource
469 * @param sequenceNumber sequence number
472 public synchronized void onObserveCompleted(List<OcHeaderOption> list,
473 OcRepresentation ocRepresentation,
474 int sequenceNumber) {
475 if (OcResource.OnObserveListener.REGISTER == sequenceNumber) {
476 msg("Observe registration action is successful:");
477 } else if (OcResource.OnObserveListener.DEREGISTER == sequenceNumber) {
478 msg("Observe De-registration action is successful");
479 } else if (OcResource.OnObserveListener.NO_OPTION == sequenceNumber) {
480 msg("Observe registration or de-registration action is failed");
483 msg("OBSERVE Result:");
484 msg("\tSequenceNumber:" + sequenceNumber);
486 mLight.setOcRepresentation(ocRepresentation);
487 } catch (OcException e) {
488 Log.e(TAG, e.toString());
489 msg("Failed to get the attribute values");
491 msg(mLight.toString());
493 if ((++mObserveCount) == 11) {
494 msg("Cancelling Observe...");
496 mFoundLightResource.cancelObserve();
497 } catch (OcException e) {
498 Log.e(TAG, e.toString());
499 msg("Error occurred while invoking \"cancelObserve\" API");
503 //prepare for the next restart of the SimpleClient
510 * An event handler to be executed whenever a "observe" request fails
512 * @param throwable exception
515 public synchronized void onObserveFailed(Throwable throwable) {
516 if (throwable instanceof OcException) {
517 OcException ocEx = (OcException) throwable;
518 Log.e(TAG, ocEx.toString());
519 ErrorCode errCode = ocEx.getErrorCode();
520 //do something based on errorCode
521 msg("Error code: " + errCode);
523 msg("Observation of the found light resource has failed");
526 //******************************************************************************
527 // End of the OIC specific code
528 //******************************************************************************
530 private final static String TAG = SimpleClient.class.getSimpleName();
531 private TextView mConsoleTextView;
532 private ScrollView mScrollView;
534 protected void onCreate(Bundle savedInstanceState) {
535 super.onCreate(savedInstanceState);
536 setContentView(R.layout.activity_simple_client);
538 mConsoleTextView = (TextView) findViewById(R.id.consoleTextView);
539 mConsoleTextView.setMovementMethod(new ScrollingMovementMethod());
540 mScrollView = (ScrollView) findViewById(R.id.scrollView);
541 mScrollView.fullScroll(View.FOCUS_DOWN);
542 final Button button = (Button) findViewById(R.id.button);
544 if (null == savedInstanceState) {
545 button.setOnClickListener(new View.OnClickListener() {
547 public void onClick(View v) {
548 button.setText("Re-start");
549 button.setEnabled(false);
550 new Thread(new Runnable() {
558 String consoleOutput = savedInstanceState.getString("consoleOutputString");
559 mConsoleTextView.setText(consoleOutput);
564 protected void onSaveInstanceState(Bundle outState) {
565 super.onSaveInstanceState(outState);
566 outState.putString("consoleOutputString", mConsoleTextView.getText().toString());
570 protected void onRestoreInstanceState(Bundle savedInstanceState) {
571 super.onRestoreInstanceState(savedInstanceState);
573 String consoleOutput = savedInstanceState.getString("consoleOutputString");
574 mConsoleTextView.setText(consoleOutput);
577 private void enableStartButton() {
578 runOnUiThread(new Runnable() {
580 Button button = (Button) findViewById(R.id.button);
581 button.setEnabled(true);
586 private void sleep(int seconds) {
588 Thread.sleep(seconds * 1000);
589 } catch (InterruptedException e) {
591 Log.e(TAG, e.toString());
595 private void msg(final String text) {
596 runOnUiThread(new Runnable() {
598 mConsoleTextView.append("\n");
599 mConsoleTextView.append(text);
600 mScrollView.fullScroll(View.FOCUS_DOWN);
606 private void printLine() {
607 msg("------------------------------------------------------------------------");
610 private synchronized void resetGlobals() {
611 mFoundLightResource = null;
612 mFoundResources.clear();
613 mLight = new Light();
618 public void onNewIntent(Intent intent) {
619 super.onNewIntent(intent);
620 Log.d(TAG, "onNewIntent with changes sending broadcast IN ");
622 Intent i = new Intent();
623 i.setAction(intent.getAction());
624 i.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES,
625 intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES));
627 Log.d(TAG, "Initialize Context again resetting");