Index: trunk/src/org/openstreetmap/josm/data/osm/NoteData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/NoteData.java	(revision 14100)
+++ trunk/src/org/openstreetmap/josm/data/osm/NoteData.java	(revision 14101)
@@ -49,4 +49,12 @@
 
     private final ListenerList<NoteDataUpdateListener> listeners = ListenerList.create();
+
+    /**
+     * Construct a new note container with a given list of notes
+     * @since 14101
+     */
+    public NoteData() {
+        this(null);
+    }
 
     /**
Index: trunk/src/org/openstreetmap/josm/gui/io/importexport/OsmChangeImporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/io/importexport/OsmChangeImporter.java	(revision 14100)
+++ trunk/src/org/openstreetmap/josm/gui/io/importexport/OsmChangeImporter.java	(revision 14101)
@@ -14,5 +14,8 @@
 import org.openstreetmap.josm.actions.ExtensionFileFilter;
 import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.NoteData;
 import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.NoteLayer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
@@ -22,4 +25,5 @@
 import org.openstreetmap.josm.io.OsmChangeReader;
 import org.openstreetmap.josm.tools.Logging;
+import org.openstreetmap.josm.tools.Pair;
 
 /**
@@ -29,9 +33,12 @@
 public class OsmChangeImporter extends FileImporter {
 
+    /**
+     * File filter for OsmChange files.
+     */
     public static final ExtensionFileFilter FILE_FILTER = ExtensionFileFilter.newFilterWithArchiveExtensions(
             "osc", "osc", tr("OsmChange File"), true);
 
     /**
-     * Constructs a new {@code OsmChangeImporter}.
+     * Constructs a new {@code OsmChangeImporter} with default file filter.
      */
     public OsmChangeImporter() {
@@ -39,4 +46,8 @@
     }
 
+    /**
+     * Constructs a new {@code OsmChangeImporter} with custom file filter.
+     * @param filter file filter
+     */
     public OsmChangeImporter(ExtensionFileFilter filter) {
         super(filter);
@@ -54,20 +65,28 @@
 
     protected void importData(InputStream in, final File associatedFile, ProgressMonitor progressMonitor) throws IllegalDataException {
-        final DataSet dataSet = OsmChangeReader.parseDataSet(in, progressMonitor);
-        final OsmDataLayer layer = new OsmDataLayer(dataSet, associatedFile.getName(), associatedFile);
-        addDataLayer(dataSet, layer, associatedFile.getPath());
+        final Pair<DataSet, NoteData> p = OsmChangeReader.parseDataSetAndNotes(in, progressMonitor);
+        final boolean hasOsmData = p.a != null && !p.a.allPrimitives().isEmpty();
+        final boolean hasNotes = p.b != null && !p.b.getNotes().isEmpty();
+        if (hasOsmData) {
+            addLayer(new OsmDataLayer(p.a, associatedFile.getName(), associatedFile));
+        }
+        if (hasNotes) {
+            addLayer(new NoteLayer(p.b, associatedFile.getName()));
+        }
+        if (!hasOsmData && !hasNotes) {
+            // FIXME: remove UI stuff from IO subsystem
+            GuiHelper.runInEDT(() -> {
+                JOptionPane.showMessageDialog(
+                        Main.parent,
+                        tr("No data found in file {0}.", associatedFile.getPath()),
+                        tr("Open OsmChange file"),
+                        JOptionPane.INFORMATION_MESSAGE);
+            });
+        }
     }
 
-    protected void addDataLayer(final DataSet dataSet, final OsmDataLayer layer, final String filePath) {
+    protected void addLayer(final Layer layer) {
         // FIXME: remove UI stuff from IO subsystem
-        //
         GuiHelper.runInEDT(() -> {
-            if (dataSet.allPrimitives().isEmpty()) {
-                JOptionPane.showMessageDialog(
-                        Main.parent,
-                        tr("No data found in file {0}.", filePath),
-                        tr("Open OsmChange file"),
-                        JOptionPane.INFORMATION_MESSAGE);
-            }
             MainApplication.getLayerManager().addLayer(layer);
             layer.onPostLoadFromFile();
Index: trunk/src/org/openstreetmap/josm/gui/layer/NoteLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/NoteLayer.java	(revision 14100)
+++ trunk/src/org/openstreetmap/josm/gui/layer/NoteLayer.java	(revision 14101)
@@ -102,4 +102,16 @@
     }
 
+    /**
+     * Create a new note layer with a notes data
+     * @param noteData Notes data
+     * @param name The name of the layer. Typically "Notes"
+     * @since 14101
+     */
+    public NoteLayer(NoteData noteData, String name) {
+        super(name);
+        this.noteData = noteData;
+        this.noteData.addNoteDataUpdateListener(this);
+    }
+
     /** Convenience constructor that creates a layer with an empty note list */
     public NoteLayer() {
Index: trunk/src/org/openstreetmap/josm/io/NoteReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/NoteReader.java	(revision 14100)
+++ trunk/src/org/openstreetmap/josm/io/NoteReader.java	(revision 14101)
@@ -11,4 +11,5 @@
 import java.util.Locale;
 import java.util.Optional;
+import java.util.function.Function;
 
 import javax.xml.parsers.ParserConfigurationException;
@@ -85,8 +86,5 @@
             if (parseMode == NoteParseMode.API) {
                 if ("note".equals(qName)) {
-                    double lat = Double.parseDouble(attrs.getValue("lat"));
-                    double lon = Double.parseDouble(attrs.getValue("lon"));
-                    LatLon noteLatLon = new LatLon(lat, lon);
-                    thisNote = new Note(noteLatLon);
+                    thisNote = parseNoteBasic(attrs);
                 }
                 return;
@@ -96,17 +94,5 @@
             switch(qName) {
             case "note":
-                double lat = Double.parseDouble(attrs.getValue("lat"));
-                double lon = Double.parseDouble(attrs.getValue("lon"));
-                LatLon noteLatLon = new LatLon(lat, lon);
-                thisNote = new Note(noteLatLon);
-                thisNote.setId(Long.parseLong(attrs.getValue("id")));
-                String closedTimeStr = attrs.getValue("closed_at");
-                if (closedTimeStr == null) { //no closed_at means the note is still open
-                    thisNote.setState(Note.State.OPEN);
-                } else {
-                    thisNote.setState(Note.State.CLOSED);
-                    thisNote.setClosedAt(DateUtils.fromString(closedTimeStr));
-                }
-                thisNote.setCreatedAt(DateUtils.fromString(attrs.getValue("created_at")));
+                thisNote = parseNoteFull(attrs);
                 break;
             case "comment":
@@ -188,4 +174,42 @@
             parsedNotes = notes;
         }
+    }
+
+    static LatLon parseLatLon(Function<String, String> attrs) {
+        double lat = Double.parseDouble(attrs.apply("lat"));
+        double lon = Double.parseDouble(attrs.apply("lon"));
+        return new LatLon(lat, lon);
+    }
+
+    static Note parseNoteBasic(Attributes attrs) {
+        return parseNoteBasic(attrs::getValue);
+    }
+
+    static Note parseNoteBasic(Function<String, String> attrs) {
+        return new Note(parseLatLon(attrs));
+    }
+
+    static Note parseNoteFull(Attributes attrs) {
+        return parseNoteFull(attrs::getValue);
+    }
+
+    static Note parseNoteFull(Function<String, String> attrs) {
+        Note note = parseNoteBasic(attrs);
+        String id = attrs.apply("id");
+        if (id != null) {
+            note.setId(Long.parseLong(id));
+        }
+        String closedTimeStr = attrs.apply("closed_at");
+        if (closedTimeStr == null) { //no closed_at means the note is still open
+            note.setState(Note.State.OPEN);
+        } else {
+            note.setState(Note.State.CLOSED);
+            note.setClosedAt(DateUtils.fromString(closedTimeStr));
+        }
+        String createdAt = attrs.apply("created_at");
+        if (createdAt != null) {
+            note.setCreatedAt(DateUtils.fromString(createdAt));
+        }
+        return note;
     }
 
Index: trunk/src/org/openstreetmap/josm/io/OsmChangeReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmChangeReader.java	(revision 14100)
+++ trunk/src/org/openstreetmap/josm/io/OsmChangeReader.java	(revision 14101)
@@ -10,7 +10,10 @@
 import javax.xml.stream.XMLStreamException;
 
+import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.NoteData;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.tools.Pair;
 
 /**
@@ -23,4 +26,6 @@
      */
     private static final String[] ACTIONS = {"create", "modify", "delete"};
+
+    protected final NoteData noteData = new NoteData();
 
     /**
@@ -80,4 +85,7 @@
                     p = parseRelation();
                     break;
+                case "note":
+                    parseNote();
+                    break;
                 default:
                     parseUnknown();
@@ -96,4 +104,35 @@
     }
 
+    private void parseNote() throws XMLStreamException {
+        LatLon location = NoteReader.parseLatLon(s -> parser.getAttributeValue(null, s));
+        String text = null;
+        while (parser.hasNext()) {
+            int event = parser.next();
+            if (event == XMLStreamConstants.START_ELEMENT) {
+                switch (parser.getLocalName()) {
+                case "comment":
+                    text = parser.getAttributeValue(null, "text");
+                    break;
+                default:
+                    parseUnknown();
+                }
+            } else if (event == XMLStreamConstants.END_ELEMENT) {
+                break;
+            }
+        }
+        if (location != null && text != null) {
+            noteData.createNote(location, text);
+        }
+    }
+
+    /**
+     * Replies the parsed notes data.
+     * @return the parsed notes data
+     * @since 14101
+     */
+    public final NoteData getNoteData() {
+        return noteData;
+    }
+
     /**
      * Parse the given input source and return the dataset.
@@ -110,3 +149,22 @@
         return new OsmChangeReader().doParseDataSet(source, progressMonitor);
     }
+
+    /**
+     * Parse the given input source and return the dataset and notes, if any (OsmAnd extends the osmChange format by adding notes).
+     *
+     * @param source the source input stream. Must not be <code>null</code>.
+     * @param progressMonitor  the progress monitor. If <code>null</code>,
+     * {@link org.openstreetmap.josm.gui.progress.NullProgressMonitor#INSTANCE} is assumed
+     *
+     * @return the dataset with the parsed data
+     * @throws IllegalDataException if the an error was found while parsing the data from the source
+     * @throws IllegalArgumentException if source is <code>null</code>
+     * @since 14101
+     */
+    public static Pair<DataSet, NoteData> parseDataSetAndNotes(InputStream source, ProgressMonitor progressMonitor)
+            throws IllegalDataException {
+        OsmChangeReader osmChangeReader = new OsmChangeReader();
+        osmChangeReader.doParseDataSet(source, progressMonitor);
+        return new Pair<>(osmChangeReader.getDataSet(), osmChangeReader.getNoteData());
+    }
 }
Index: trunk/test/unit/org/openstreetmap/josm/actions/mapmode/AddNoteActionTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/actions/mapmode/AddNoteActionTest.java	(revision 14100)
+++ trunk/test/unit/org/openstreetmap/josm/actions/mapmode/AddNoteActionTest.java	(revision 14101)
@@ -5,9 +5,6 @@
 import static org.junit.Assert.assertTrue;
 
-import java.util.Collections;
-
 import org.junit.Rule;
 import org.junit.Test;
-import org.openstreetmap.josm.data.notes.Note;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.NoteData;
@@ -39,5 +36,5 @@
         try {
             MainApplication.getLayerManager().addLayer(layer);
-            AddNoteAction mapMode = new AddNoteAction(new NoteData(Collections.<Note>emptyList()));
+            AddNoteAction mapMode = new AddNoteAction(new NoteData());
             MapFrame map = MainApplication.getMap();
             MapMode oldMapMode = map.mapMode;
Index: trunk/test/unit/org/openstreetmap/josm/data/osm/NoteDataTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/data/osm/NoteDataTest.java	(revision 14100)
+++ trunk/test/unit/org/openstreetmap/josm/data/osm/NoteDataTest.java	(revision 14101)
@@ -20,5 +20,5 @@
     @Test
     public void testNoteData() {
-        NoteData empty = new NoteData(null);
+        NoteData empty = new NoteData();
         assertEquals(0, empty.getNotes().size());
         NoteData notEmpty = new NoteData(Arrays.asList(new Note(LatLon.ZERO)));
Index: trunk/test/unit/org/openstreetmap/josm/io/OsmChangeReaderTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/io/OsmChangeReaderTest.java	(revision 14101)
+++ trunk/test/unit/org/openstreetmap/josm/io/OsmChangeReaderTest.java	(revision 14101)
@@ -0,0 +1,70 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.notes.Note;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.NoteData;
+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.tools.Pair;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * Unit tests of {@link OsmChangeReader}.
+ */
+public class OsmChangeReaderTest {
+
+    /**
+     * Setup rule
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules();
+
+    /**
+     * Parse osmChange.
+     * @param osm OSM data in osmChange format, without header/footer
+     * @return data set
+     * @throws Exception if any error occurs
+     */
+    private static Pair<DataSet, NoteData> parse(String osm) throws Exception {
+        try (InputStream in = new ByteArrayInputStream((
+                "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>\n" +
+                "<osmChange generator=\"test\" version=\"0.6\">" + osm + "</osmChange>")
+                .getBytes(StandardCharsets.UTF_8))) {
+            return OsmChangeReader.parseDataSetAndNotes(in, NullProgressMonitor.INSTANCE);
+        }
+    }
+
+    /**
+     * Checks reading of OsmAnd notes.
+     * @throws Exception never
+     */
+    @Test
+    public void testNotes() throws Exception {
+        NoteData nd = parse(
+                "<create>\r\n" +
+                "    <note lat=\"50.23887555404037\" lon=\"13.358299552342795\" id=\"-2\">\r\n" +
+                "      <comment text=\"something\" />\r\n" +
+                "    </note>\r\n" +
+                "  </create>\r\n" +
+                "  <modify />\r\n" +
+                "  <delete />").b;
+        Collection<Note> notes = nd.getNotes();
+        assertEquals(1, notes.size());
+        Note n = notes.iterator().next();
+        assertEquals(new LatLon(50.23887555404037, 13.358299552342795), n.getLatLon());
+        assertEquals("something", n.getFirstComment().getText());
+    }
+}
