Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/

package com.codenameone.developerguide.snippets.generated;

import com.codename1.gpu.*;
import com.codename1.ui.*;
import com.codename1.ui.animations.*;
import com.codename1.ui.events.*;
import com.codename1.ui.geom.*;
import com.codename1.ui.layouts.*;
import com.codename1.ui.list.*;
import com.codename1.ui.plaf.*;
import com.codename1.ui.util.*;
import com.codename1.components.*;
import com.codename1.charts.models.*;
import com.codename1.charts.renderers.*;
import com.codename1.charts.views.*;
import com.codename1.capture.*;
import com.codename1.io.*;
import com.codename1.l10n.*;
import com.codename1.location.*;
import com.codename1.maps.*;
import com.codename1.media.*;
import com.codename1.messaging.*;
import com.codename1.payment.*;
import com.codename1.processing.*;
import com.codename1.properties.*;
import com.codename1.push.*;
import com.codename1.security.*;
import com.codename1.social.*;
import com.codename1.ui.spinner.*;
import java.io.*;
import com.codename1.mapping.*;
import com.codename1.xml.*;
import java.util.*;
import com.codename1.annotations.*;
import com.codename1.properties.*;

class AnnotationJsonXmlMappingJava003Snippet {

// tag::annotation-json-xml-mapping-java-003[]
// A type from a third-party jar the build cannot annotate.
static class LatLon {
double lat;
double lon;
}

static class LatLonMapper implements Mapper<LatLon> {
@Override
public Class<LatLon> type() {
return LatLon.class;
}

@Override
public Map<String, Object> toMap(LatLon instance) {
Map<String, Object> m = new LinkedHashMap<String, Object>();
m.put("lat", Double.valueOf(instance.lat));
m.put("lon", Double.valueOf(instance.lon));
return m;
}

@Override
public LatLon fromMap(Map<String, Object> map) {
LatLon out = new LatLon();
out.lat = readDouble(map.get("lat"));
out.lon = readDouble(map.get("lon"));
return out;
}

@Override
public String xmlRootName() {
return "latLon";
}

@Override
public void writeXml(LatLon instance, Element root) {
root.setAttribute("lat", String.valueOf(instance.lat));
root.setAttribute("lon", String.valueOf(instance.lon));
}

@Override
public LatLon readXml(Element root) {
LatLon out = new LatLon();
out.lat = Double.parseDouble(root.getAttribute("lat"));
out.lon = Double.parseDouble(root.getAttribute("lon"));
return out;
}

// JSONParser hands back a Double for every number, but a map that came
// from somewhere else may hold any Number. Read through the interface
// rather than casting to Double: a failed cast does not throw on iOS,
// so the catch you would write for it never runs.
private double readDouble(Object value) {
return value instanceof Number ? ((Number) value).doubleValue() : 0;
}
}

void registerMappers() {
Mappers.register(new LatLonMapper());
}
// end::annotation-json-xml-mapping-java-003[]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/

package com.codenameone.developerguide.snippets.generated;

import com.codename1.gpu.*;
import com.codename1.ui.*;
import com.codename1.ui.animations.*;
import com.codename1.ui.events.*;
import com.codename1.ui.geom.*;
import com.codename1.ui.layouts.*;
import com.codename1.ui.list.*;
import com.codename1.ui.plaf.*;
import com.codename1.ui.util.*;
import com.codename1.components.*;
import com.codename1.charts.models.*;
import com.codename1.charts.renderers.*;
import com.codename1.charts.views.*;
import com.codename1.capture.*;
import com.codename1.io.*;
import com.codename1.l10n.*;
import com.codename1.location.*;
import com.codename1.maps.*;
import com.codename1.media.*;
import com.codename1.messaging.*;
import com.codename1.payment.*;
import com.codename1.processing.*;
import com.codename1.properties.*;
import com.codename1.push.*;
import com.codename1.security.*;
import com.codename1.social.*;
import com.codename1.ui.spinner.*;
import java.io.*;
import java.util.*;


class MiscellaneousFeaturesJava010Snippet {

// tag::miscellaneous-features-java-010[]
void ensureLocationUsageDescription() {
// Both calls only work in the simulator, and setProjectBuildHint throws
// anywhere else -- so this belongs behind an isSimulator() check, run
// once during development rather than on every launch.
if (!Display.getInstance().isSimulator()) {
return;
}

Map<String, String> hints = Display.getInstance().getProjectBuildHints();
if (hints == null) {
// No codename1_settings.properties beside the running project, or
// it could not be read. Nothing to check against, and nothing to
// write into.
return;
}

String description = hints.get("ios.locationUsageDescription");
Comment thread
shai-almog marked this conversation as resolved.
if (description == null || description.length() == 0) {
Display.getInstance().setProjectBuildHint("ios.locationUsageDescription",
"Used to show nearby results on the map");
}
}
// end::miscellaneous-features-java-010[]
}
5 changes: 5 additions & 0 deletions docs/developer-guide/Annotation-JSON-XML-Mapping.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ persisted across builds.
Sometimes a class lives in a third-party JAR the build can't annotate.
Hand-write a `Mapper<T>` and register it at startup:

[source,java]
----
include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/AnnotationJsonXmlMappingJava003Snippet.java[tag=annotation-json-xml-mapping-java-003,indent=0]
----


Hand-written mappers take precedence over generated ones for the same
class.
5 changes: 5 additions & 0 deletions docs/developer-guide/Miscellaneous-Features.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,11 @@ A good example for a common problem developers face is location code that doesn'

To solve this sort of used case you have two APIs in `Display`:

[source,java]
----
include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/MiscellaneousFeaturesJava010Snippet.java[tag=miscellaneous-features-java-010,indent=0]
----


Both of these allow you to detect if a build hint is set and if not (or if it's set incorrectly) set its value...

Expand Down
17 changes: 16 additions & 1 deletion docs/developer-guide/SVG-Transcoder.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,23 @@ no SVGs gets no weaving.
=== Calling the registry yourself

If you don't use `theme.css` but still want a transcoded SVG, construct
the generated class directly:
the generated class directly. It lands in
`com.codename1.generated.svg` and is named after the file, so
`src/main/svg/logo.svg` becomes `com.codename1.generated.svg.Logo`.
The class exists only after a build has run the transcoder, which is why
this listing isn't one of the compiled examples:

[listing]
----
import com.codename1.generated.svg.Logo;
import com.codename1.ui.Display;

Logo logo = new Logo(); // declared size at DENSITY_MEDIUM
Logo dense = new Logo(Display.DENSITY_HIGH); // read as a higher-density design
Logo sized = new Logo(12f, 12f); // 12mm square, converted per device

myButton.setIcon(sized);
----

Constructors come in three flavours, matching the three CSS sizing
mechanisms above. The two-`float` constructor takes millimeters; that's
Expand Down
28 changes: 25 additions & 3 deletions docs/developer-guide/security.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ Notice that this is a temporary roadblock as any savvy hacker would compile the

NOTE: This isn't encoding or encryption — it's a simple obfuscation of the data.

There are two simple methods in the `Util` class:

The `Util` class has two static methods for it: `xorEncode(String)` turns a string into the obfuscated form, and `xorDecode(String)` turns it back.

They use a simple xor based obfuscation to make a String less readable. For example, if you've code like this:

Expand Down Expand Up @@ -90,8 +89,31 @@ This works through a new mechanism in storage where you can replace the storage
include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/SecurityJava030Snippet.java[tag=security-java-030,indent=0]
----

You can leverage that knowledge to change the encryption password on the encryption storage using pseudo-code like this:
You can leverage that knowledge to change the encryption password on the encryption storage. The key is installed for the whole of `Storage`, so every entry has to move together: read them all under the old key, install the new one, write them all back. `EncryptedStorage` comes from the bouncy castle cn1lib, so this listing isn't part of the compiled examples:

[listing]
----
EncryptedStorage.install(oldKey);
Map<String, byte[]> all = new LinkedHashMap<>();
for (String name : Storage.getInstance().listEntries()) {
try (InputStream is = Storage.getInstance().createInputStream(name)) {
all.put(name, Util.readInputStream(is));
}
}

EncryptedStorage.install(newKey);
for (Map.Entry<String, byte[]> e : all.entrySet()) {
try (OutputStream o = Storage.getInstance().createOutputStream(e.getKey())) {
o.write(e.getValue());
}
Comment thread
shai-almog marked this conversation as resolved.
}
----

The `try`-with-resources is deliberate: `Util.cleanup` swallows a close failure, and on the write side a swallowed close means an entry was never finalized under the new key. Let it throw.

WARNING: This isn't crash-safe, and it can't be made crash-safe from the outside. If the process dies part way through the second loop, some entries are under each key and neither opens the whole store. `Storage` has no rename, so there is no way to stage the converted copies and swap them in atomically, and the recovery data lives only in that in-memory map.

Which is the real argument for not rotating the storage key at all. Encrypt `Storage` with a random key your app generates once, keep that key wrapped under the password-derived one in a single record outside `Storage`, and a password change re-wraps that one small record instead of rewriting every entry. Nothing else moves, so there is no half-converted state to recover from. If you do rewrite the store in place, do it once at startup with nothing else touching `Storage`, and treat the possibility of an interrupted run as something your app has to survive rather than something this loop prevents.

NOTE: It isn't a good idea to replace storage objects when an app is running so this is purely for this special case...

Expand Down
5 changes: 0 additions & 5 deletions scripts/developer-guide/missing-code-blocks-baseline.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
# Prose that promises a code block where none follows.
# A ratchet: entries may be removed as holes are filled, never added.
# Regenerate with check-missing-code-blocks.py --write-baseline.
Annotation-JSON-XML-Mapping.asciidoc Hand-write a `Mapper<T>` and register it at startup:
Authentication-And-Identity.asciidoc Firebase Auth isn't an OIDC provider -- it issues Google-Identity-Toolkit-style tokens via REST endpoints. `com.codename1.social.FirebaseAuth` wraps those endpoints:
Maven-Creating-CN1Libs.adoc Now try it out. Try adding the following code to your application project's main class (or anywhere in the application project, for that matter):
Maven-Creating-CN1Libs.adoc The simulator dispatches every action on the Codename One EDT through `Display.callSerially`, so your method can call `Display.getInstance()`, `Form.show()`, `Dialog.show()`, `ToastBar.showInfoMessage()` and any other CN1 API. Reflection uses the same classloader that loaded `Display`, so cn1lib internals (including package-private classes) resolve normally:
Miscellaneous-Features.asciidoc To solve this sort of used case you have two APIs in `Display`:
SVG-Transcoder.asciidoc the generated class directly:
The-Components-Of-Codename-One.asciidoc Call the builder from a Maven plugin, an Ant task or a one-shot `main`:
The-Components-Of-Codename-One.asciidoc This code should output "The result was 7" to the console. It's fully asynchronous, so you can include this code anywhere without worrying about it "bogging down" your code. The full signature of this form of the https://www.codenameone.com/javadoc/com/codename1/ui/BrowserComponent.html#execute(java.lang.String,com.codename1.util.SuccessCallback)[execute()] method is:
io.asciidoc In the above code you do the following:
Expand All @@ -16,5 +13,3 @@ io.asciidoc There are many methods of interest to keep an eye for:
io.asciidoc database by name:
performance.asciidoc In the new Contacts demo you have a share button for each contact, the code for constructing a `ShareButton` looks like this:
performance.asciidoc These icons are in a shared resource file that you load and don't cache. The initial workaround was to cache this resource but a better solution was to convert this code:
security.asciidoc There are two simple methods in the `Util` class:
security.asciidoc You can leverage that knowledge to change the encryption password on the encryption storage using pseudo-code like this:
Loading