Skip to content
Open
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
6 changes: 6 additions & 0 deletions .github/workflows/car-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ jobs:
- uses: actions/checkout@v6
- name: Set TMPDIR
run: echo "TMPDIR=${{ runner.temp }}" >> $GITHUB_ENV
- name: Free Disk Space
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android/sdk/ndk
sudo rm -rf /opt/ghc
sudo rm -rf /usr/share/swift
- name: Cache codenameone-tools
uses: actions/cache@v5
with:
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/scripts-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ jobs:
- name: Set TMPDIR
run: echo "TMPDIR=${{ runner.temp }}" >> $GITHUB_ENV
- name: Free Disk Space
if: matrix.id != 'default'
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android/sdk/ndk
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@

/** Android Calendar Provider integration. */
final class AndroidCalendarSource extends LocalCalendarSource {
// Events and Instances use the same Calendar Provider selection column.
private static final String CALENDAR_ID_SELECTION_COLUMN = Events.CALENDAR_ID;
private static final String[] EVENT_COLUMNS = {Events._ID, Events.CALENDAR_ID, Events.TITLE,
Events.DESCRIPTION, Events.EVENT_LOCATION, Events.DTSTART, Events.DTEND, Events.DURATION,
Events.EVENT_TIMEZONE, Events.ALL_DAY, Events.RRULE, Events.STATUS, Events.AVAILABILITY,
Expand Down Expand Up @@ -119,9 +121,8 @@ private CalendarPage<CalendarEvent> queryEventsBlocking(CalendarQuery query)
List<String> args = new ArrayList<String>();
boolean expandInstances = query != null
&& (query.getStartTime() != null || query.getEndTime() != null);
String calendarColumn = expandInstances ? Instances.CALENDAR_ID : Events.CALENDAR_ID;
if (query != null && query.getCalendarId() != null) {
where.append(" AND ").append(calendarColumn).append("=?");
where.append(" AND ").append(CALENDAR_ID_SELECTION_COLUMN).append("=?");
args.add(query.getCalendarId());
}
where.append(" AND ").append(Events.DELETED).append("=0");
Expand Down
6 changes: 3 additions & 3 deletions docs/developer-guide/Advanced-Topics-Under-The-Hood.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -786,8 +786,8 @@ This is great as it allows apps to be installed with a single click and no permi

===== Enabling permissions

// vale-skip: write-good.TooWordy — 'minimum of API 33' is the precise term for the SDK floor.
Codename One's Gradle 8 based Android builder detects the highest Android SDK you've installed and uses that value (with a minimum of API 33) for both the compile and target SDK versions, so the modern runtime permission flow is enabled by default. If you override the target version through the `android.targetSDKVersion` build hint the builder will honour it, but lowering the target may disable some compatibility libraries. Keeping the target current is strongly recommended for Play Store compliance.
// vale-skip: write-good.TooWordy — 'minimum of API 36' is the precise term for the SDK floor.
By default, Codename One's Gradle 8 based Android builder uses the highest Android SDK you've installed, with a minimum of API 36, for both the compile and target SDK versions. If you override the target through the `android.targetSDKVersion` build hint, the builder honors it while keeping the compile SDK at least as high as the target SDK. Lowering the target may disable some compatibility libraries. Keeping the target current is strongly recommended for Play Store compliance.

===== Permission prompts

Expand All @@ -803,7 +803,7 @@ If you explicitly lower the target SDK (for example: `android.targetSDKVersion=2
.Install UI when using the old permissions system
image::img/marshmallow-permissions-level21.png[Install UI when using the old permissions system,scaledwidth=20%]

When you keep the default target (API 33+) the installer defers to the runtime permission flow and the installation UI looks like this instead:
When you keep the default target (API 36+) the installer defers to the runtime permission flow and the installation UI looks like this instead:

.Install UI when using the new permissions system
image::img/marshmallow-permissions-level23.png[Install UI when using the new permissions system,scaledwidth=20%]
Expand Down
4 changes: 2 additions & 2 deletions maven/android/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<configuration>
<effort>Max</effort>
<threshold>Low</threshold>
<failOnError>false</failOnError>
<failOnError>true</failOnError>
Comment thread
shai-almog marked this conversation as resolved.
<xmlOutput>true</xmlOutput>
<xmlOutputDirectory>${project.build.directory}</xmlOutputDirectory>
<excludeFilterFile>${project.basedir}/../../Ports/Android/spotbugs-exclude.xml</excludeFilterFile>
Comment thread
shai-almog marked this conversation as resolved.
Expand All @@ -53,7 +53,7 @@
<id>spotbugs</id>
<phase>verify</phase>
<goals>
<goal>spotbugs</goal>
<goal>check</goal>
</goals>
Comment thread
shai-almog marked this conversation as resolved.
</execution>
Comment thread
shai-almog marked this conversation as resolved.
</executions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -759,10 +759,12 @@ public boolean build(File sourceZip, final BuildRequest request) throws BuildExc
}

if (useGradle8) {
// Build Tools and platform SDK versions are independent; compileSdk is
// raised to at least targetSdk when the Gradle project is generated below.
maxBuildToolsVersionInt = Math.max(33, maxBuildToolsVersionInt);
maxBuildToolsVersion = "" + maxBuildToolsVersionInt;

maxPlatformVersionInt = Math.max(33, maxPlatformVersionInt);
maxPlatformVersionInt = Math.max(36, maxPlatformVersionInt);
maxPlatformVersion = "" + maxPlatformVersionInt;
Comment thread
shai-almog marked this conversation as resolved.
}

Expand Down Expand Up @@ -4995,6 +4997,7 @@ public void usesClassMethod(String cls, String method) {
compileSdkVersion = "36";
supportLibVersion = "28";
}
compileSdkVersion = ensureCompileSdkAtLeastTarget(compileSdkVersion, targetNumber);
jcenter =
" google()\n" +
" jcenter()\n" +
Expand Down Expand Up @@ -6200,7 +6203,23 @@ private void initPlayServiceVersions(BuildRequest request) {
}
}

private Integer parseSdkInt(String value) {
// Package-private for direct unit testing; this is not part of the builder API.
static String ensureCompileSdkAtLeastTarget(String compileSdkVersion, String targetSdkVersion) {
Integer compileSdkInt = parseSdkInt(compileSdkVersion);
Integer targetSdkInt = parseSdkInt(targetSdkVersion);
if (targetSdkInt == null) {
return compileSdkVersion;
}
if (compileSdkVersion == null || compileSdkVersion.trim().isEmpty()) {
return String.valueOf(targetSdkInt);
}
if (compileSdkInt != null && targetSdkInt > compileSdkInt) {
return String.valueOf(targetSdkInt);
}
return compileSdkVersion;
}
Comment thread
shai-almog marked this conversation as resolved.
Comment thread
shai-almog marked this conversation as resolved.

private static Integer parseSdkInt(String value) {
if (value == null) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2026, 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.codename1.builders;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class AndroidGradleBuilderSdkVersionTest {

@Test
void raisesCompileSdkToTargetSdk() {
assertEquals("36",
AndroidGradleBuilder.ensureCompileSdkAtLeastTarget("33", "36"));
}

@Test
void doesNotLowerCompileSdk() {
assertEquals("36",
AndroidGradleBuilder.ensureCompileSdkAtLeastTarget("36", "35"));
}

@Test
void handlesLegacyCompileSdkNotation() {
assertEquals("36",
AndroidGradleBuilder.ensureCompileSdkAtLeastTarget("'android-21'", "36"));
}

@Test
void preservesNonNumericCompileSdk() {
assertEquals("'android-Baklava'",
AndroidGradleBuilder.ensureCompileSdkAtLeastTarget("'android-Baklava'", "36"));
}

@Test
void suppliesMissingCompileSdk() {
assertEquals("36",
AndroidGradleBuilder.ensureCompileSdkAtLeastTarget(null, "36"));
}
}
Loading