// -------------------------------------------------------
  // Property: unsubscribeNotifications
  // -------------------------------------------------------
  public void unsubscribeNotifications(final CompletionHandler handler) throws MiotException {
    if (handler == null) {
      throw new IllegalArgumentException("handler is null");
    }

    PropertyInfo propertyInfo = PropertyInfoFactory.create(getService());
    for (Property property : getService().getProperties()) {
      PropertyDefinition definition = property.getDefinition();
      if (definition.isNotifiable()) {
        propertyInfo.addProperty(property);
      }
    }

    DeviceManipulator op = MiotManager.getDeviceManipulator();
    op.removePropertyChangedListener(
        propertyInfo,
        new DeviceManipulator.CompletionHandler() {
          @Override
          public void onSucceed() {
            handler.onSucceed();
          }

          @Override
          public void onFailed(int errCode, String description) {
            handler.onFailed(errCode, description);
          }
        });
  }
  // -------------------------------------------------------
  // Property: subscribeNotifications
  // -------------------------------------------------------
  public void subscribeNotifications(
      final CompletionHandler handler, final PropertyNotificationListener listener)
      throws MiotException {
    if (handler == null) {
      throw new IllegalArgumentException("handler is null");
    }

    if (listener == null) {
      throw new IllegalArgumentException("listener is null");
    }

    PropertyInfo propertyInfo = PropertyInfoFactory.create(getService());
    for (Property property : getService().getProperties()) {
      PropertyDefinition definition = property.getDefinition();
      if (definition.isNotifiable()) {
        propertyInfo.addProperty(property);
      }
    }

    DeviceManipulator op = MiotManager.getDeviceManipulator();
    op.addPropertyChangedListener(
        propertyInfo,
        new DeviceManipulator.CompletionHandler() {
          @Override
          public void onSucceed() {
            handler.onSucceed();
          }

          @Override
          public void onFailed(int errCode, String description) {
            handler.onFailed(errCode, description);
          }
        },
        new DeviceManipulator.PropertyChangedListener() {
          @Override
          public void onPropertyChanged(PropertyInfo info, String propertyName) {
            switch (propertyName) {
              case PROPERTY_UsbStatus:
                Boolean usbStatus = (Boolean) info.getValue(PROPERTY_UsbStatus);
                listener.onUsbStatusChanged(usbStatus);
                break;
              case PROPERTY_PowerStatus:
                Boolean powerStatus = (Boolean) info.getValue(PROPERTY_PowerStatus);
                listener.onPowerStatusChanged(powerStatus);
                break;

              default:
                break;
            }
          }
        });
  }