docs: def _properties_changed(self,
                              object_path,
                              interface_name,
                              changed_properties,
                              invalidated_properties):
          """
          Internal method.
  
          Called when a DBusProperty of any managed object changes.
          """
          # update device state:
          old_state = deepcopy(self._objects[object_path])
          for property_name in invalidated_properties:
              del self._objects[object_path][interface_name][property_name]
          for key, value in changed_properties.items():
              self._objects[object_path][interface_name][key] = value
          new_state = self._objects[object_path]
          # detect changes and trigger events:
          if interface_name == Interface['Drive']:
              self._detect_toggle(
                  'has_media',
                  self.get(object_path, old_state),
                  self.get(object_path, new_state),
                  'media_added', 'media_removed')
          elif interface_name == Interface['Filesystem']:
              self._detect_toggle(
                  'is_mounted',
                  self.get(object_path, old_state),
                  self.get(object_path, new_state),
                  'device_mounted', 'device_unmounted')
          self.trigger('device_changed',
                       self.get(object_path, old_state),
                       self.get(object_path, new_state))