use of com.codename1.rad.ui.UI in project CodenameOne by codenameone.
the class TooltipManager method showTooltip.
/**
* Shows the actual tooltip, this is invoked when the time for the tooltip
* elapses. It shows the tooltip UI immediately
*
* @param tip the tooltip text
* @param cmp the component
*/
protected void showTooltip(final String tip, final Component cmp) {
currentTooltip = new InteractionDialog(new BorderLayout());
TextArea text = new TextArea(tip);
text.setGrowByContent(true);
text.setEditable(false);
text.setFocusable(false);
text.setActAsLabel(true);
text.setUIID(textUIID);
currentTooltip.setUIID(dialogUIID);
currentTooltip.setDialogUIID("Container");
currentTooltip.add(BorderLayout.CENTER, text);
currentTooltip.setAnimateShow(false);
currentTooltip.showPopupDialog(cmp, true);
}
use of com.codename1.rad.ui.UI in project CodenameOne by codenameone.
the class AndroidGradleBuilder method build.
@Override
public boolean build(File sourceZip, final BuildRequest request) throws BuildException {
debug("Request Args: ");
debug("-----------------");
for (String arg : request.getArgs()) {
debug(arg + "=" + request.getArg(arg, null));
}
debug("-------------------");
String defaultAndroidHome = isMac ? path(System.getProperty("user.home"), "Library", "Android", "sdk") : is_windows ? path(System.getProperty("user.home"), "AppData", "Local", "Android", "sdk") : // linux
path(System.getProperty("user.home"), "Android", "Sdk");
String androidHome = System.getenv("ANDROID_HOME");
if (androidHome == null) {
androidHome = defaultAndroidHome;
}
File androidSDKDir;
String bat = "";
if (is_windows) {
bat = ".bat";
}
androidSDKDir = new File(androidHome);
if (!androidSDKDir.exists()) {
throw new BuildException("Cannot find Android SDK at " + androidHome + ". Please install Android studio, or set the ANDROID_HOME environment variable to point to your android sdk directory.");
}
File sdkmanager = new File(androidSDKDir, path("tools", "bin", "sdkmanager" + bat));
String sdkListStr;
try {
sdkListStr = execString(tmpDir, sdkmanager.getAbsolutePath(), "--list");
} catch (Exception ex) {
error("Failed to get SDK list using " + sdkmanager + ". " + ex.getMessage(), ex);
throw new BuildException("Failed to get SDK list using " + sdkmanager, ex);
}
Scanner sdkScanner = new Scanner(sdkListStr);
List<String> installedPlatforms = new ArrayList<>();
List<String> installedBuildToolsVersions = new ArrayList<>();
while (sdkScanner.hasNextLine()) {
String line = sdkScanner.nextLine().trim();
if (line.startsWith("build-tools;")) {
String[] columns = line.split("\\|");
if (columns.length >= 4) {
// If there are only 3 columns, then this is not referring to an installed build-tools
// but an available one.
String[] col1Parts = columns[0].split(";");
if (col1Parts.length > 1) {
installedBuildToolsVersions.add(col1Parts[1].trim());
}
}
} else if (line.startsWith("platforms;")) {
String[] columns = line.split("\\|");
if (columns.length > 1) {
String[] col1Parts = columns[0].split(";");
String platform = col1Parts[1].trim();
if (platform.contains("-")) {
platform = platform.substring(platform.indexOf("-") + 1);
}
installedPlatforms.add(platform);
}
}
}
debug("Installed platforms: " + installedPlatforms);
int maxBuildToolsVersionInt = 0;
String maxBuildToolsVersion = "0";
for (String ver : installedBuildToolsVersions) {
int verInt = parseVersionStringAsInt(ver);
if (verInt > maxBuildToolsVersionInt) {
maxBuildToolsVersion = ver;
maxBuildToolsVersionInt = verInt;
}
}
int maxPlatformVersionInt = 0;
String maxPlatformVersion = "0";
for (String ver : installedPlatforms) {
int verInt = parseVersionStringAsInt(ver);
if (verInt > maxPlatformVersionInt) {
maxPlatformVersionInt = verInt;
maxPlatformVersion = ver;
}
}
if (maxPlatformVersionInt == 0) {
maxPlatformVersionInt = 30;
maxPlatformVersion = "30";
}
if (maxBuildToolsVersionInt == 0) {
maxBuildToolsVersionInt = 30;
maxBuildToolsVersion = "30";
}
useAndroidX = request.getArg("android.useAndroidX", "false").equals("true");
migrateToAndroidX = useAndroidX && request.getArg("android.migrateToAndroidX", "true").equals("true");
buildToolsVersionInt = maxBuildToolsVersionInt;
this.buildToolsVersion = request.getArg("android.buildToolsVersion", "" + maxBuildToolsVersion);
String buildToolsVersionIntStr = this.buildToolsVersion;
if (buildToolsVersionIntStr.indexOf(".") > 1) {
buildToolsVersionIntStr = buildToolsVersionIntStr.substring(0, buildToolsVersionIntStr.indexOf("."));
}
buildToolsVersionInt = Integer.parseInt(buildToolsVersionIntStr.replaceAll("[^0-9]", ""));
if (useAndroidX && buildToolsVersionInt < 29) {
buildToolsVersionInt = 29;
this.buildToolsVersion = "29";
} else if (buildToolsVersionInt > 28 && !useAndroidX) {
useAndroidX = true;
migrateToAndroidX = useAndroidX && request.getArg("android.migrateToAndroidX", "true").equals("true");
}
debug("Effective build tools version = " + this.buildToolsVersion);
// Augment the xpermissions request arg with explicit android.permissions.XXX build hints
xPermissions = request.getArg("android.xpermissions", "");
debug("Adding android permissions...");
for (String xPerm : ANDROID_PERMISSIONS) {
String permName = xPerm.substring(xPerm.lastIndexOf(".") + 1);
if (request.getArg("android.permission." + permName, "false").equals("true")) {
debug("Found permission " + permName);
String maxSdk = request.getArg("android.permission." + permName + ".maxSdkVersion", "");
String required = request.getArg("android.permission." + permName + ".required", "");
String addString = " <uses-permission android:name=\"" + xPerm + "\" ";
if (!"".equals(required)) {
addString += "android:required=\"" + required + "\" ";
}
if (!"".equals(maxSdk)) {
addString += "android:maxSdkVersion=\"" + maxSdk + "\" ";
}
addString += "/>\n";
xPermissions += permissionAdd(request, xPerm, addString);
}
}
File tmpFile = getBuildDirectory();
if (tmpFile == null) {
throw new IllegalStateException("Build directory must be set before running build.");
}
if (tmpFile.exists()) {
delTree(tmpFile);
}
tmpFile.mkdirs();
File managedGradleHome = new File(path(System.getProperty("user.home"), ".codenameone", "gradle"));
String gradleHome = System.getenv("GRADLE_HOME");
if (gradleHome == null && managedGradleHome.exists()) {
gradleHome = managedGradleHome.getAbsolutePath();
}
String gradleExe = System.getenv("GRADLE_PATH");
if (gradleExe == null) {
if (gradleHome != null) {
gradleExe = new File(gradleHome + File.separator + "bin" + File.separator + "gradle" + bat).getAbsolutePath();
} else {
gradleExe = "gradle";
}
}
if (PREFER_MANAGED_GRADLE) {
debug("PREFER_MANAGED_GRADLE flag is set. Ignoring GRADLE_HOME and GRADLE_PATH environment variables. Using managed gradle at " + managedGradleHome + " instead");
gradleHome = managedGradleHome.getAbsolutePath();
gradleExe = new File(managedGradleHome, path("bin", "gradle" + bat)).getAbsolutePath();
}
String gradleVersion;
try {
gradleVersion = getGradleVersion(gradleExe);
} catch (Exception ex) {
gradleVersion = "0";
}
debug("FOUND gradleVersion " + gradleVersion);
int gradleVersionInt = parseVersionStringAsInt(gradleVersion);
debug("Found gradleVersionInt=" + gradleVersionInt);
if (gradleVersionInt < MIN_GRADLE_VERSION) {
// The minimum version is too low.
if (managedGradleHome.exists()) {
gradleExe = new File(managedGradleHome, path("bin", "gradle" + bat)).getAbsolutePath();
try {
gradleVersion = getGradleVersion(gradleExe);
} catch (Exception ex) {
gradleVersion = "0";
}
gradleVersionInt = parseVersionStringAsInt(gradleVersion);
}
if (gradleVersionInt < MIN_GRADLE_VERSION) {
if (managedGradleHome.exists()) {
delTree(managedGradleHome);
}
File gradleZip = new File(managedGradleHome + ".zip");
if (gradleZip.exists()) {
gradleZip.delete();
}
try {
log("Downloading gradle distribution from " + gradleDistributionUrl);
FileUtils.copyURLToFile(new URL(gradleDistributionUrl), gradleZip);
} catch (Exception ex) {
throw new BuildException("Failed to download gradle distribution from URL " + gradleDistributionUrl, ex);
}
try {
ZipFile gradleZipFile = new ZipFile(gradleZip);
File extracted = new File(path(gradleZip.getAbsolutePath() + "-extracted"));
extracted.mkdir();
gradleZipFile.extractAll(extracted.getAbsolutePath());
gradleZip.delete();
for (File extractedChild : extracted.listFiles()) {
if (extractedChild.getName().startsWith("gradle") && extractedChild.isDirectory()) {
extractedChild.renameTo(managedGradleHome);
break;
}
}
} catch (ZipException zex) {
throw new BuildException("Failed to unzip gradle distribution after downloading it", zex);
}
if (!managedGradleHome.exists()) {
throw new BuildException("There was a problem extracting the gradle distribution. Expected it to be extracted at " + managedGradleHome + ", but was not found");
}
File managedGradleExe = new File(managedGradleHome, path("bin", "gradle" + bat));
if (!managedGradleExe.exists()) {
throw new BuildException("Expected to find gradle executable at " + managedGradleExe + " after download and extraction, but it wasn't there. Something about the gradle install must have failed. Try again.");
}
gradleExe = managedGradleExe.getAbsolutePath();
try {
gradleVersion = getGradleVersion(gradleExe);
} catch (Exception ex) {
throw new BuildException("Failed to get gradle version even after downloading it from " + gradleDistributionUrl + ". Something must have gone wrong with the gradle installation.");
}
gradleVersionInt = parseVersionStringAsInt(gradleVersion);
if (gradleVersionInt < MIN_GRADLE_VERSION) {
throw new BuildException("Required gradle version is " + MIN_GRADLE_VERSION + " but found version " + gradleVersion);
}
}
}
File androidToolsDir = new File(androidSDKDir, "tools");
File androidCommand = new File(androidToolsDir, "android" + bat);
File projectDir = new File(tmpFile, request.getMainClass());
gradleProjectDirectory = projectDir;
String androidVersion = "android-14";
String defaultVersion = maxPlatformVersion;
String usesLibrary = " <uses-library android:name=\"org.apache.http.legacy\" android:required=\"false\" />\n";
String targetNumber = request.getArg("android.targetSDKVersion", defaultVersion);
if (!targetNumber.equals(defaultVersion)) {
try {
if (Integer.parseInt(targetNumber) < 28) {
usesLibrary = "";
}
} catch (Exception err) {
}
}
String targetSDKVersion = targetNumber;
final int targetSDKVersionInt = Integer.parseInt(targetSDKVersion);
if (targetSDKVersionInt > 14) {
androidVersion = "android-" + targetSDKVersion;
}
targetSDKVersion = " android:targetSdkVersion=\"" + targetSDKVersion + "\" ";
log("TargetSDKVersion=" + targetSDKVersion);
String gradlePluginVersion = "1.3.1";
if (gradleVersionInt < 3) {
gradlePluginVersion = "2.0.0";
} else {
if (gradleVersionInt < 6) {
if (useAndroidX) {
gradlePluginVersion = "3.2.0";
} else {
gradlePluginVersion = "3.0.1";
}
} else {
gradlePluginVersion = "4.1.1";
}
}
boolean androidAppBundle = request.getArg("android.appBundle", gradleVersionInt >= 5 ? "true" : "false").equals("true");
debug("gradlePluginVersion=" + gradlePluginVersion);
projectDir = new File(projectDir, "app");
File studioProjectDir = projectDir.getParentFile();
if (isUnitTestMode()) {
throw new BuildException("Unit Test mode not currently supported for local android builds.");
} else {
try {
log("Creating AndroidStudioProject from template");
if (studioProjectDir.exists()) {
delTree(studioProjectDir);
}
createAndroidStudioProject(studioProjectDir);
} catch (Exception ex) {
error("Failed to create AndroidStudioProject: " + ex.getMessage(), ex);
throw new BuildException("Failed to create android project", ex);
}
}
File assetsDir = new File(projectDir + "/src/main", "assets");
assetsDir.mkdirs();
File resDir = new File(projectDir + "/src/main", "res");
resDir.mkdirs();
File valsDir = new File(resDir, "values");
valsDir.mkdirs();
File vals11Dir = null;
vals11Dir = new File(resDir, "values-v11");
vals11Dir.mkdirs();
File vals21Dir = null;
vals21Dir = new File(resDir, "values-v21");
vals21Dir.mkdirs();
File layoutDir = new File(resDir, "layout");
layoutDir.mkdirs();
File xmlDir = new File(resDir, "xml");
xmlDir.mkdirs();
File srcDir = new File(projectDir, "src/main/java");
srcDir.mkdirs();
File dummyClassesDir = new File(tmpFile, "Classes");
dummyClassesDir.mkdirs();
File libsDir = new File(projectDir, "libs");
libsDir.mkdirs();
try {
debug("Extracting " + sourceZip);
unzip(sourceZip, dummyClassesDir, assetsDir, srcDir, libsDir, xmlDir);
} catch (Exception ex) {
throw new BuildException("Failed to extract source zip " + sourceZip, ex);
}
File appDir = buildToolsVersionInt >= 27 ? new File(srcDir.getParentFile(), "app") : new File(libsDir.getParentFile(), "app");
File googleServicesJson = new File(appDir, "google-services.json");
googleServicesJson = new File(libsDir.getParentFile(), "google-services.json");
try {
if (!retrolambda(new File(System.getProperty("user.dir")), request, dummyClassesDir)) {
return false;
}
} catch (Exception ex) {
throw new BuildException("Failed to run retrolambda on classes", ex);
}
String additionalImports = request.getArg("android.activityClassImports", "");
String additionalMembers = request.getArg("android.activityClassBody", "");
String additionalKeyVals = "";
String mopubActivities = "";
String mopubBannerXML = "";
String permissions = "";
String telephonyRequired = "false";
String aarDependencies = "";
// move dependant projects to a separate directory
File[] childs = libsDir.listFiles();
for (int i = 0; i < childs.length; i++) {
File file = childs[i];
if (file.getName().endsWith(".andlib")) {
throw new BuildException("andlib format is not supported anymore, use aar instead");
}
if (file.getName().endsWith(".aar")) {
String name = file.getName().substring(0, file.getName().lastIndexOf("."));
if (request.getArg("android.arrimplementation", "").contains(name)) {
aarDependencies += " implementation(name:'" + name + "', ext:'aar')\n";
} else {
aarDependencies += " compile(name:'" + name + "', ext:'aar')\n";
}
}
}
String minSDK = request.getArg("android.min_sdk_version", "15");
String facebookSupport = "";
String facebookProguard = "";
String facebookActivityMetaData = "";
String facebookActivity = "";
String facebookHashCode = "";
boolean facebookSupported = request.getArg("facebook.appId", null) != null;
if (facebookSupported) {
facebookHashCode = " try {\n" + " android.content.pm.PackageInfo info = getPackageManager().getPackageInfo(\n" + " \"" + request.getPackageName() + "\", android.content.pm.PackageManager.GET_SIGNATURES);\n" + " for (android.content.pm.Signature signature : info.signatures){\n" + " java.security.MessageDigest md = java.security.MessageDigest.getInstance(\"SHA\");\n" + " md.update(signature.toByteArray());\n" + " android.util.Log.d(\"KeyHash:\", android.util.Base64.encodeToString(md.digest(), android.util.Base64.DEFAULT));\n" + " Display.getInstance().setProperty(\"facebook_hash\", android.util.Base64.encodeToString(md.digest(), android.util.Base64.DEFAULT));\n" + " }\n" + " } catch (android.content.pm.PackageManager.NameNotFoundException e) {\n" + " e.printStackTrace();\n" + " } catch (java.security.NoSuchAlgorithmException e) {\n" + " e.printStackTrace();\n" + " }\n\n";
String permissionsStr = request.getArg("android.facebook_permissions", "\"public_profile\",\"email\",\"user_friends\"");
permissionsStr = request.getArg("and.facebook_permissions", permissionsStr);
permissionsStr = permissionsStr.replace('"', ' ');
facebookSupport = "Display.getInstance().setProperty(\"facebook_app_id\", \"" + request.getArg("facebook.appId", "706695982682332") + "\");\n" + " Display.getInstance().setProperty(\"facebook_permissions\", \"" + permissionsStr + "\");\n" + " com.codename1.social.FacebookImpl.init();\n";
facebookProguard = "-keep class com.facebook.** { *; }\n" + "-keepattributes Signature\n" + "-dontwarn bolts.**\n" + "-dontnote android.support.**\n" + "-dontnote androidx.**";
facebookActivityMetaData = " <meta-data android:name=\"com.facebook.sdk.ApplicationId\" android:value=\"@string/facebook_app_id\"/>\n";
facebookActivity = " <activity android:name=\"com.facebook.FacebookActivity\"/>\n";
additionalKeyVals += "<string name=\"facebook_app_id\">" + request.getArg("facebook.appId", "706695982682332") + "</string>";
}
String googlePlayAdsMetaData = "";
String googlePlayAdsActivity = "";
String googlePlayObfuscation = "";
String googleAdUnitId = request.getArg("android.googleAdUnitId", request.getArg("google.adUnitId", null));
String googlePlayAdViewCode = "";
if (googleAdUnitId != null && googleAdUnitId.length() > 0) {
minSDK = maxInt("9", minSDK);
googlePlayAdsMetaData = "<meta-data android:name=\"com.google.android.gms.version\" android:value=\"@integer/google_play_services_version\"/>";
googlePlayAdsActivity = "<activity android:name=\"com.google.android.gms.ads.AdActivity\" android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize\"/>";
accessNetworkStatePermission = true;
String testDevice = request.getArg("android.googleAdUnitTestDevice", "C6783E2486F0931D9D09FABC65094FDF");
googlePlayAdViewCode = " com.google.android.gms.ads.AdView adView = new com.google.android.gms.ads.AdView(this);\n" + " adView.setAdUnitId(\"" + googleAdUnitId + "\");\n" + " adView.setId(2002);\n" + " adView.setAdSize(com.google.android.gms.ads.AdSize.SMART_BANNER);\n" + " AndroidImplementation.setViewAboveBelow(null, adView, 0, com.google.android.gms.ads.AdSize.SMART_BANNER.getHeightInPixels(this));\n" + " com.google.android.gms.ads.AdRequest adRequest = new com.google.android.gms.ads.AdRequest.Builder().addTestDevice(\"" + testDevice + "\").build();\n" + " adView.loadAd(adRequest);\n";
googlePlayObfuscation = "-keep class * extends java.util.ListResourceBundle {\n" + " protected Object[][] getContents();\n" + "}\n" + "\n" + "-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {\n" + " public static final *** NULL;\n" + "}\n" + "\n" + "-keepnames @com.google.android.gms.common.annotation.KeepName class *\n" + "-keepclassmembernames class * {\n" + " @com.google.android.gms.common.annotation.KeepName *;\n" + "}\n" + "\n" + "-keepnames class * implements android.os.Parcelable {\n" + " public static final ** CREATOR;\n" + "}\n";
}
playServicesVersion = request.getArg("android.playServicesVersion", playServicesVersion);
final String playServicesValue = request.getArg("android.includeGPlayServices", null);
playFlag = "true";
gpsPermission = request.getArg("android.gpsPermission", "false").equals("true");
try {
scanClassesForPermissions(dummyClassesDir, new Executor.ClassScanner() {
@Override
public void usesClass(String cls) {
if (cls.indexOf("com/codename1/notifications") == 0) {
recieveBootCompletedPermission = true;
}
if (cls.indexOf("com/codename1/capture") == 0) {
capturePermission = true;
}
if (cls.indexOf("com/codename1/ads") == 0) {
debug("Adding phone permission because of class " + cls);
phonePermission = true;
}
if (cls.indexOf("com/codename1/components/Ads") == 0) {
debug("Adding phone permission because of class " + cls);
phonePermission = true;
}
if (cls.indexOf("com/codename1/maps") == 0 || cls.indexOf("com/codename1/location") == 0) {
gpsPermission = true;
}
if (cls.indexOf("com/codename1/push") > -1) {
pushPermission = true;
}
if (cls.indexOf("com/codename1/contacts") > -1) {
contactsReadPermission = true;
}
if (cls.indexOf("com/codename1/payment") > -1) {
purchasePermissions = true;
}
if (cls.indexOf("com/codename1/location/Geofence") > -1) {
if (!"true".equals(playServicesValue)) {
// If play services are not currently "blanket" enabled
// we will enable them here
debug("Adding location playservice");
request.putArgument("android.location.minPlayServicesVersion", "12.0.1");
playServicesLocation = true;
playFlag = "false";
if (targetSDKVersionInt >= 29) {
backgroundLocationPermission = true;
}
}
}
if (cls.indexOf("com/codename1/social") > -1) {
credentialsPermission = true;
getAccountsPermission = true;
}
}
@Override
public void usesClassMethod(String cls, String method) {
if (cls.indexOf("com/codename1/ui/Display") == 0 && (method.indexOf("vibrate") > -1 || method.indexOf("notifyStatusBar") > -1)) {
vibratePermission = true;
}
if ((cls.indexOf("com/codename1/media/MediaManager") == 0 && method.indexOf("createBackgroundMedia") > -1)) {
if (targetSDKVersionInt >= 28) {
foregroundServicePermission = true;
}
}
if ((cls.indexOf("com/codename1/ui/Display") == 0 && method.indexOf("createBackgroundMedia") > -1)) {
if (targetSDKVersionInt >= 28) {
foregroundServicePermission = true;
}
}
if (cls.indexOf("com/codename1/location/LocationManager") == 0 && (method.indexOf("addGeoFencing") > -1 || method.indexOf("setBackgroundLocationListener") > -1)) {
if (!"true".equals(playServicesValue)) {
if (targetSDKVersionInt >= 29) {
backgroundLocationPermission = true;
}
}
}
if (cls.indexOf("com/codename1/location/LocationManager") == 0 && (method.indexOf("addGeoFencing") > -1 || method.indexOf("getLocationManager") > -1)) {
if (!"true".equals(playServicesValue)) {
// If play services are not currently "blanket" enabled
// we will enable them here
debug("Adding location playservice");
request.putArgument("android.location.minPlayServicesVersion", "12.0.1");
playServicesLocation = true;
playFlag = "false";
}
}
if (cls.indexOf("com/codename1/media/MediaManager") == 0 && method.indexOf("setRemoteControlListener") > -1) {
debug("Adding wake lock permission due to use of MediaManager.setRemoteControlListener");
// smsPermission = true;
wakeLock = true;
addRemoteControlService = true;
}
if (cls.indexOf("com/codename1/ui/Display") == 0 && method.indexOf("getUdid") > -1) {
debug("Adding phone permission because of Display.getUdid method");
phonePermission = true;
}
if (cls.indexOf("com/codename1/ui/Display") == 0 && method.indexOf("getMsisdn") > -1) {
phonePermission = true;
}
if (cls.indexOf("com/codename1/ui/Display") == 0 && method.indexOf("getAllContacts") > -1) {
contactsReadPermission = true;
}
if (cls.indexOf("com/codename1/ui/Display") == 0 && method.indexOf("lockScreen") > -1) {
wakeLock = true;
}
if (cls.indexOf("com/codename1/ui/Display") == 0 && method.indexOf("setScreenSaverEnabled") > -1) {
wakeLock = true;
}
if (cls.indexOf("com/codename1/media/MediaManager") == 0 && method.indexOf("createMediaRecorder") > -1) {
recordAudio = true;
}
if (cls.indexOf("com/codename1/ui/Display") == 0 && method.indexOf("createMediaRecorder") > -1) {
recordAudio = true;
}
if (cls.indexOf("com/codename1/ui/Display") == 0 && method.indexOf("createContact") > -1) {
contactsWritePermission = true;
}
if (cls.indexOf("com/codename1/ui/Display") == 0 && method.indexOf("deleteContact") > -1) {
contactsWritePermission = true;
}
if (cls.indexOf("com/codename1/contacts/ContactsManager") == 0 && method.indexOf("createContact") > -1) {
contactsWritePermission = true;
}
if (cls.indexOf("com/codename1/contacts/ContactsManager") == 0 && method.indexOf("deleteContact") > -1) {
contactsWritePermission = true;
}
}
});
} catch (IOException ex) {
throw new BuildException("An error occurred while trying to scan the classes for API usage.", ex);
}
boolean useFCM = pushPermission && "fcm".equalsIgnoreCase(request.getArg("android.messagingService", "fcm"));
if (useFCM) {
request.putArgument("android.fcm.minPlayServicesVersion", "12.0.1");
}
debug("Starting playServicesVersion " + playServicesVersion);
for (String arg : request.getArgs()) {
if (arg.endsWith(".minPlayServicesVersion")) {
if (compareVersions(request.getArg(arg, null), playServicesVersion) > 0) {
playServicesVersion = request.getArg(arg, null);
debug("playServicesVersion increased to " + playServicesVersion + " due to " + arg);
}
}
}
request.putArgument("android.playServicesVersion", playServicesVersion);
debug("-----USING PLAY SERVICES VERSION " + playServicesVersion + "----");
if (useFCM) {
if (!googleServicesJson.exists()) {
error("google-services.json not found. When using FCM for push notifications (i.e. android.messagingService=fcm), you must include valid google-services.json file. Use the Firebase console to add Firebase messaging to your app. https://console.firebase.google.com/u/0/ Then download the google-services.json file and place it in the native/android directory of your project. If you still want to use GCM (which no longer works) define the build hint android.messagingService=gcm", new RuntimeException());
return false;
}
if (buildToolsVersionInt < 27) {
error("FCM push notifications require build tools version 27 or higher. Please set the android.buildToolsVersion to 27.0.0 or higher or remove the android.messagingService=fcm build hint.", new RuntimeException());
return false;
}
if (!request.getArg("android.topDependency", "").contains("com.google.gms:google-services")) {
request.putArgument("android.topDependency", request.getArg("android.topDependency", "") + "\n classpath 'com.google.gms:google-services:4.0.1'\n");
}
if (!request.getArg("android.xgradle", "").contains("apply plugin: 'com.google.gms.google-services'")) {
request.putArgument("android.xgradle", request.getArg("android.xgradle", "") + "\napply plugin: 'com.google.gms.google-services'\n");
}
if (!request.getArg("gradleDependencies", "").contains("com.google.firebase:firebase-core")) {
debug("Adding firebase core to gradle dependencies.");
debug("Play services version: " + request.getArg("var.android.playServicesVersion", ""));
debug("gradleDependencies before: " + request.getArg("gradleDependencies", ""));
request.putArgument("gradleDependencies", request.getArg("gradleDependencies", "") + "\ncompile \"com.google.firebase:firebase-core:${var.android.playServicesVersion}\"\n");
debug("gradleDependencies after: " + request.getArg("gradleDependencies", ""));
}
if (!request.getArg("gradleDependencies", "").contains("com.google.firebase:firebase-messaging")) {
request.putArgument("gradleDependencies", request.getArg("gradleDependencies", "") + "\ncompile \"com.google.firebase:firebase-messaging:${var.android.playServicesVersion}\"\n");
}
}
// if a flag is declared we don't want the default play flag to be true
if (request.getArg("android.playService.plus", null) != null || request.getArg("android.playService.auth", (googleServicesJson.exists()) ? "true" : null) != null || request.getArg("android.playService.base", null) != null || request.getArg("android.playService.identity", null) != null || request.getArg("android.playService.indexing", null) != null || request.getArg("android.playService.appInvite", null) != null || request.getArg("android.playService.analytics", null) != null || request.getArg("android.playService.cast", null) != null || request.getArg("android.playService.gcm", null) != null || request.getArg("android.playService.drive", null) != null || request.getArg("android.playService.fitness", null) != null || request.getArg("android.playService.location", null) != null || request.getArg("android.playService.maps", null) != null || request.getArg("android.playService.ads", null) != null || request.getArg("android.playService.vision", null) != null || request.getArg("android.playService.nearby", null) != null || request.getArg("android.playService.panorama", null) != null || request.getArg("android.playService.games", null) != null || request.getArg("android.playService.safetynet", null) != null || request.getArg("android.playService.wallet", null) != null || request.getArg("android.playService.wearable", null) != null || request.getArg("android.playService.ads", null) != null) {
playFlag = "false";
}
boolean legacyGplayServicesMode = false;
if (playServicesValue != null) {
if (playServicesValue.equals("true")) {
// compatibility mode...
legacyGplayServicesMode = true;
if (playFlag.equals("false")) {
// legacy gplay can't be mixed with explicit gplay fail the build right now!
if (googleServicesJson.exists()) {
debug("The android.playService.auth flag was automatically enabled because the project includes the google-services.json file");
}
error("Error: you can't use the build hint android.includeGPlayServices together with android.playService.* build hints. They are exclusive of one another. Please remove the old android.includeGPlayServices hint from your code or from the cn1lib that might have injected it", new RuntimeException());
return false;
}
playFlag = "true";
} else {
playFlag = "false";
}
}
playServicesPlus = request.getArg("android.playService.plus", "false").equals("true");
playServicesAuth = request.getArg("android.playService.auth", (Boolean.valueOf(playFlag) || googleServicesJson.exists()) ? "true" : "false").equals("true");
playServicesBase = request.getArg("android.playService.base", playFlag).equals("true");
playServicesIdentity = request.getArg("android.playService.identity", "false").equals("true");
playServicesIndexing = request.getArg("android.playService.indexing", "false").equals("true");
playServicesInvite = request.getArg("android.playService.appInvite", "false").equals("true");
playServicesAnalytics = request.getArg("android.playService.analytics", playFlag).equals("true");
playServicesCast = request.getArg("android.playService.cast", "false").equals("true");
playServicesGcm = request.getArg("android.playService.gcm", playFlag).equals("true") || request.getArg("gcm.sender_id", null) != null;
playServicesDrive = request.getArg("android.playService.drive", "false").equals("true");
playServicesFit = request.getArg("android.playService.fitness", "false").equals("true");
playServicesLocation = playServicesLocation || request.getArg("android.playService.location", playFlag).equals("true");
playServicesMaps = request.getArg("android.playService.maps", playFlag).equals("true");
playServicesAds = request.getArg("android.playService.ads", playFlag).equals("true");
if (request.getArg("android.googleAdUnitId", request.getArg("google.adUnitId", null)) != null) {
playServicesAds = true;
}
playServicesVision = request.getArg("android.playService.vision", "false").equals("true");
playServicesNearBy = request.getArg("android.playService.nearby", "false").equals("true");
playServicesSafetyPanorama = request.getArg("android.playService.panorama", "false").equals("true");
playServicesGames = request.getArg("android.playService.games", "false").equals("true");
playServicesSafetyNet = request.getArg("android.playService.safetynet", "false").equals("true");
playServicesWallet = request.getArg("android.playService.wallet", "false").equals("true");
playServicesWear = request.getArg("android.playService.wearable", "false").equals("true");
if (googleAdUnitId == null && playServicesAds) {
minSDK = maxInt("9", minSDK);
googlePlayAdsMetaData = "<meta-data android:name=\"com.google.android.gms.version\" android:value=\"@integer/google_play_services_version\"/>";
}
if (playServicesLocation) {
debug("Play Services Location Enabled");
googlePlayObfuscation += "-keep class com.codename1.location.AndroidLocationPlayServiceManager {\n" + "*;\n" + "}\n\n";
googlePlayObfuscation += "-keep class com.codename1.location.BackgroundLocationHandler {\n" + "*;\n" + "}\n\n";
googlePlayObfuscation += "-keep class com.codename1.location.BackgroundLocationBroadcastReceiver {\n" + "*;\n" + "}\n\n";
googlePlayObfuscation += "-keep class com.codename1.impl.android.BackgroundFetchHandler {\n" + "*;\n" + "}\n\n";
googlePlayObfuscation += "-keep class com.codename1.location.GeofenceHandler {\n" + "*;\n" + "}\n\n";
googlePlayObfuscation += "-keep class com.codename1.location.CodenameOneBackgroundLocationActivity {\n" + "*;\n" + "}\n\n";
} else {
debug("Play services location disabled");
}
shouldIncludeGoogleImpl = playServicesAuth;
if (shouldIncludeGoogleImpl) {
googlePlayObfuscation += "-keep class com.codename1.social.GoogleImpl {\n" + "*;\n" + "}\n\n";
}
File stubFileSourceDir = new File(srcDir, request.getPackageName().replace('.', File.separatorChar));
stubFileSourceDir.mkdirs();
String headphonesVars = "";
String headphonesOnResume = "";
if (request.getArg("android.headphoneCallback", "false").equals("true")) {
headphonesVars = " HeadSetReceiver myHeadphoneReceiver;\n\n" + " public static void headphonesConnected() {\n" + " i.headphonesConnected();" + " }" + " public static void headphonesDisconnected() {\n" + " i.headphonesDisconnected();" + " }";
headphonesOnResume = " HeadSetReceiver myReceiver = new HeadSetReceiver();\n" + " IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);\n" + " registerReceiver(myReceiver, filter);\n";
File headphonesFile = new File(stubFileSourceDir, "HeadSetReceiver.java");
String stubSourceCode = "package " + request.getPackageName() + ";\n\n" + "import android.content.Context;\n" + "import android.content.Intent;\n" + "import android.content.IntentFilter;\n" + "import android.content.BroadcastReceiver;\n\n" + "public class HeadSetReceiver extends BroadcastReceiver {\n" + " @Override public void onReceive(Context context, Intent intent) {\n" + " if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {\n" + " int state = intent.getIntExtra(\"state\", -1);\n" + " switch (state) {\n" + " case 0:\n" + " " + request.getMainClass() + "Stub.headphonesDisconnected();\n" + " break;\n" + " case 1:\n" + " " + request.getMainClass() + "Stub.headphonesConnected();\n" + " break;\n" + " }\n" + " }\n" + " }\n" + "}";
try {
createFile(headphonesFile, stubSourceCode.getBytes());
} catch (IOException ex) {
throw new BuildException("Failed to create HeadSetReceiver class", ex);
}
}
if (request.getArg("noExtraResources", "false").equals("true")) {
new File(assetsDir, "CN1Resource.res").delete();
new File(assetsDir, "androidTheme.res").delete();
new File(assetsDir, "android_holo_light.res").delete();
}
if (getAndroidPortSrcJar() == null) {
try {
setAndroidPortSrcJar(getResourceAsFile("/com/codename1/android/android_port_sources.jar", ".jar"));
} catch (IOException ex) {
throw new BuildException("Failed to find android_port_sources.jar");
}
}
if (!getAndroidPortSrcJar().exists()) {
throw new IllegalStateException("Configuration error. Cannot find androidPortSrcJar at " + getAndroidPortSrcJar());
}
try {
unzip(androidPortSrcJar, srcDir, assetsDir, srcDir);
} catch (IOException ex) {
throw new BuildException("Failed to extract android port sources from " + androidPortSrcJar, ex);
}
// We need to choose the correct PlayServices class file for the version of play services
// we are building for.
File androidImpl = new File(srcDir, "com/codename1/impl/android");
File playServicesClassFile = getPlayServicesJavaSourceFile(srcDir, playServicesVersion);
String playServicesClassName = playServicesClassFile.getName().substring(0, playServicesClassFile.getName().indexOf("."));
// Delete all of the PlayServices_X_X_X files that we aren't going to use
for (File f : androidImpl.listFiles()) {
if (f.getName().startsWith("PlayServices_") && f.getName().endsWith(".java")) {
if (!f.equals(playServicesClassFile)) {
f.delete();
}
}
}
if (!playServicesClassFile.getName().equals("PlayServices.java")) {
// We will change the instance of the PlayServices class used to the most recent one we selected
// The AndroidImplementation class has call to PlayServices.setInstance(...) in its init
// method which we will update here.
File androidImplementation = new File(androidImpl, "AndroidImplementation.java");
try {
if (playServicesLocation) {
replaceInFile(androidImplementation, "new PlayServices()", "new com.codename1.impl.android." + playServicesClassName + "()");
replaceInFile(androidImplementation, "new com.codename1.impl.android.PlayServices()", "new com.codename1.impl.android." + playServicesClassName + "()");
} else {
replaceInFile(androidImplementation, "PlayServices.setInstance(", "//PlayServices.setInstance(");
}
} catch (IOException ex) {
throw new BuildException("Failed to inject settings into PlayServices class.", ex);
}
}
if (targetSDKVersionInt >= 29) {
File androidLocationPlayServicesManager = new File(srcDir, "com/codename1/location/AndroidLocationPlayServicesManager.java");
if (androidLocationPlayServicesManager.exists()) {
try {
replaceInFile(androidLocationPlayServicesManager, "//29+", "");
} catch (IOException ex) {
throw new BuildException("Failed to activate lines in " + androidLocationPlayServicesManager + " for API 29+");
}
}
}
xQueries = "";
if (targetSDKVersionInt >= 30) {
xQueries = "<queries>\n" + request.getArg("android.manifest.queries", "") + "</queries>\n";
}
// Delete the Facebook implemetation if this app does not use FB.
if (!facebookSupported) {
File fb = new File(srcDir, "com/codename1/social/FacebookImpl.java");
fb.delete();
} else {
// special case for pubnub that includes a cn1lib for json that masks the one defined in Android
File json = new File(dummyClassesDir, "org/json");
if (json.exists()) {
delTree(json);
}
}
if (!playServicesLocation) {
File fb = new File(srcDir, "com/codename1/location/AndroidLocationPlayServiceManager.java");
fb.delete();
fb = new File(srcDir, "com/codename1/location/BackgroundLocationHandler.java");
fb.delete();
fb = new File(srcDir, "com/codename1/location/BackgroundLocationBroadcastReceiver.java");
fb.delete();
fb = new File(srcDir, "com/codename1/location/GeofenceHandler.java");
fb.delete();
fb = new File(srcDir, "com/codename1/location/CodenameOneBackgroundLocationActivity.java");
fb.delete();
for (File f : androidImpl.listFiles()) {
if (f.getName().startsWith("PlayServices_") && f.getName().endsWith(".java")) {
f.delete();
} else if (f.getName().equals("PlayServices.java")) {
f.delete();
}
}
}
if (!shouldIncludeGoogleImpl) {
File fb = new File(srcDir, "com/codename1/social/GoogleImpl.java");
fb.delete();
}
final String moPubAdUnitId = request.getArg("android.mopubId", null);
if (moPubAdUnitId != null && moPubAdUnitId.length() > 0) {
integrateMoPub = true;
}
if (request.getArg("android.textureView", "false").equals("true")) {
File impl = new File(srcDir, "com" + File.separator + "codename1" + File.separator + "impl" + File.separator + "android" + File.separator + "AndroidImplementation.java");
try {
replaceInFile(impl, "public static boolean textureView = false;", "public static boolean textureView = true;");
} catch (IOException ex) {
throw new BuildException("Failed to process android.textureView build hint", ex);
}
}
if (request.getArg("android.hideStatusBar", "false").equals("true")) {
File impl = new File(srcDir, "com" + File.separator + "codename1" + File.separator + "impl" + File.separator + "android" + File.separator + "AndroidImplementation.java");
try {
replaceInFile(impl, "statusBarHidden;", "statusBarHidden = true;");
} catch (IOException ex) {
throw new BuildException("Failed to process android.hideStatusBar build hint", ex);
}
}
if (request.getArg("android.asyncPaint", "true").equals("true")) {
File impl = new File(srcDir, "com" + File.separator + "codename1" + File.separator + "impl" + File.separator + "android" + File.separator + "AndroidImplementation.java");
try {
replaceInFile(impl, "public static boolean asyncView = false;", "public static boolean asyncView = true;");
} catch (IOException ex) {
throw new BuildException("Failed to process android.asyncPaint build hint", ex);
}
}
if (request.getArg("android.keyboardOpen", "true").equals("true")) {
File impl = new File(srcDir, "com" + File.separator + "codename1" + File.separator + "impl" + File.separator + "android" + File.separator + "AndroidImplementation.java");
try {
replaceInFile(impl, "private boolean asyncEditMode = false;", "private boolean asyncEditMode = true;");
} catch (IOException ex) {
throw new BuildException("Failed to process android.keyboardOpen build hint", ex);
}
}
// String sdkVersion = request.getArg("android.targetSDKVersion", defaultVersion);
if (targetNumber != null) {
if (Integer.parseInt(targetNumber) >= 17) {
try {
File androidBrowserComponentCallback = new File(srcDir, "com" + File.separator + "codename1" + File.separator + "impl" + File.separator + "android" + File.separator + "AndroidBrowserComponentCallback.java");
replaceInFile(androidBrowserComponentCallback, "//import android.webkit.JavascriptInterface;", "import android.webkit.JavascriptInterface;");
replaceInFile(androidBrowserComponentCallback, "//@JavascriptInterface", "@JavascriptInterface");
} catch (Exception e) {
// swallow this and continue.
}
}
}
File drawableDir = new File(resDir, "drawable");
drawableDir.mkdirs();
File drawableHdpiDir = new File(resDir, "drawable-hdpi");
drawableHdpiDir.mkdirs();
File drawableLdpiDir = new File(resDir, "drawable-ldpi");
drawableLdpiDir.mkdirs();
File drawableMdpiDir = new File(resDir, "drawable-mdpi");
drawableMdpiDir.mkdirs();
File drawableXhdpiDir = new File(resDir, "drawable-xhdpi");
drawableXhdpiDir.mkdirs();
File drawableXXhdpiDir = new File(resDir, "drawable-xxhdpi");
drawableXXhdpiDir.mkdirs();
File drawableXXXhdpiDir = new File(resDir, "drawable-xxxhdpi");
drawableXXXhdpiDir.mkdirs();
try {
BufferedImage iconImage = ImageIO.read(new ByteArrayInputStream(request.getIcon()));
createIconFile(new File(drawableDir, "icon.png"), iconImage, 128, 128);
createIconFile(new File(drawableHdpiDir, "icon.png"), iconImage, 72, 72);
createIconFile(new File(drawableLdpiDir, "icon.png"), iconImage, 36, 36);
createIconFile(new File(drawableMdpiDir, "icon.png"), iconImage, 48, 48);
createIconFile(new File(drawableXhdpiDir, "icon.png"), iconImage, 96, 96);
createIconFile(new File(drawableXXhdpiDir, "icon.png"), iconImage, 144, 144);
createIconFile(new File(drawableXXXhdpiDir, "icon.png"), iconImage, 192, 192);
File notifFile = new File(assetsDir, "ic_stat_notify.png");
if (notifFile.exists()) {
BufferedImage bi = ImageIO.read(notifFile);
createIconFile(new File(drawableDir, "ic_stat_notify.png"), bi, 24, 24);
notifFile.delete();
} else {
// with white
if (Integer.parseInt(targetNumber) >= 21) {
// notification small icon
Image img = makeColorTransparent(iconImage, new Color(iconImage.getRGB(2, 2)));
BufferedImage notifSmallIcon = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D bGr = notifSmallIcon.createGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();
iconImage = notifSmallIcon;
}
createIconFile(new File(drawableDir, "ic_stat_notify.png"), iconImage, 24, 24);
}
} catch (IOException ex) {
throw new BuildException("Failed to generate icon files", ex);
}
if (!purchasePermissions) {
File billingSupport = new File(srcDir, path("com", "codename1", "impl", "android", "BillingSupport.java"));
if (billingSupport.exists()) {
billingSupport.delete();
}
}
try {
zipDir(new File(libsDir, "userClasses.jar").getAbsolutePath(), dummyClassesDir.getAbsolutePath());
} catch (Exception ex) {
throw new BuildException("Failed to create userClasses.jar", ex);
}
File stringsFile = new File(valsDir, "strings.xml");
String stringsFileContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<resources>\n" + " <string name=\"app_name\">" + xmlize(request.getDisplayName()).replace("'", "\\'") + "</string>\n" + additionalKeyVals + request.getArg("android.stringsXml", "") + "</resources>";
try {
OutputStream stringsSourceStream = new FileOutputStream(stringsFile);
stringsSourceStream.write(stringsFileContent.getBytes());
stringsSourceStream.close();
String locales = request.getArg("android.locales", null);
if (locales != null && locales.length() > 0) {
for (String loc : locales.split(";")) {
File currentValuesDir = new File(valsDir.getParent(), "values-" + loc);
currentValuesDir.mkdirs();
File currentStringsFile = new File(currentValuesDir, "strings.xml");
stringsSourceStream = new FileOutputStream(currentStringsFile);
stringsSourceStream.write(stringsFileContent.getBytes());
stringsSourceStream.close();
}
}
} catch (IOException ex) {
error("Failed to generate strings file", ex);
throw new BuildException("Failed to generate strings file " + stringsFile, ex);
}
// declare the android native theme.
File stylesFile = new File(valsDir, "styles.xml");
File colors = new File(valsDir, "colors.xml");
String colorsStr = "";
if (colors.exists()) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
// Using factory get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
Document dom = db.parse(colors);
NodeList nl = dom.getElementsByTagName("color");
for (int i = 0; i < nl.getLength(); i++) {
Node color = nl.item(i);
NamedNodeMap attr = color.getAttributes();
Node key = attr.getNamedItem("name");
String k = key.getNodeValue();
colorsStr += "<item name=\"android:" + k + "\">@color/" + k + "</item>\n";
}
} catch (Exception e) {
error("Failed to create DocumentBuilder", e);
}
}
String themeName = "android:Theme.Black";
String itemName = androidAppBundle ? "cn1Style" : "attr/cn1Style";
String stylesFileContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<resources>\n" + " <style name=\"CustomTheme\" parent=\"" + themeName + "\">\n" + " <item name=\"" + itemName + "\">@style/CN1.EditText.Style</item>\n" + " </style>\n" + " <attr name=\"cn1Style\" format=\"reference\" />\n" + " <style name=\"CN1.EditText.Style\" parent=\"@android:style/Widget.EditText\">\n" + " <item name=\"android:textCursorDrawable\">@null</item>\n" + " </style>\n" + request.getArg("android.style", "") + "</resources>";
try {
OutputStream stylesSourceStream = new FileOutputStream(stylesFile);
stylesSourceStream.write(stylesFileContent.getBytes());
stylesSourceStream.close();
String theme = request.getArg("android.theme", "Light");
if (theme.length() > 0 && theme.equalsIgnoreCase("Dark")) {
theme = "";
} else {
theme = "." + theme;
}
File styles11File = new File(vals11Dir, "styles.xml");
String styles11FileContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<resources>\n" + " <style name=\"CustomTheme\" parent=\"@android:style/Theme.Holo" + theme + "\">\n" + " <item name=\"" + itemName + "\">@style/CN1.EditText.Style</item>\n" + " <item name=\"android:windowActionBar\">false</item>\n" + " <item name=\"android:windowTitleSize\">0dp</item>\n" + " </style>\n" + " <style name=\"CN1.EditText.Style\" parent=\"@android:style/Widget.EditText\">\n" + " <item name=\"android:textCursorDrawable\">@null</item>\n" + " </style>\n" + "</resources>\n";
OutputStream styles11SourceStream = new FileOutputStream(styles11File);
styles11SourceStream.write(styles11FileContent.getBytes());
styles11SourceStream.close();
File styles21File = new File(vals21Dir, "styles.xml");
String styles21FileContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<resources>\n" + " <style name=\"CustomTheme\" parent=\"@android:style/Theme.Material" + theme + "\">\n" + " <item name=\"" + itemName + "\">@style/CN1.EditText.Style</item>\n" + " <item name=\"android:windowActionBar\">false</item>\n" + " <item name=\"android:windowTitleSize\">0dp</item>\n" + colorsStr + " </style>\n" + " <style name=\"CN1.EditText.Style\" parent=\"@android:style/Widget.EditText\">\n" + " <item name=\"android:textCursorDrawable\">@null</item>\n" + " </style>\n" + "</resources>\n";
OutputStream styles21SourceStream = new FileOutputStream(styles21File);
styles21SourceStream.write(styles21FileContent.getBytes());
styles21SourceStream.close();
} catch (IOException ex) {
error("Failed to generate style files", ex);
throw new BuildException("Failed to generate styles files", ex);
}
try {
File layoutFile = new File(layoutDir, "main.xml");
String layoutFileContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " android:layout_width=\"fill_parent\"\n" + " android:layout_height=\"fill_parent\"\n" + request.getArg("android.xlayout_attr", "") + " android:background=\"#ff000000\" >\n" + mopubBannerXML + "</RelativeLayout>\n";
OutputStream layoutSourceStream = new FileOutputStream(layoutFile);
layoutSourceStream.write(layoutFileContent.getBytes());
layoutSourceStream.close();
String customLayout = request.getArg("android.cusom_layout1", null);
int counter = 1;
while (customLayout != null) {
File customFile = new File(layoutDir, "cusom_layout" + counter + ".xml");
layoutSourceStream = new FileOutputStream(customFile);
layoutSourceStream.write(customLayout.getBytes());
layoutSourceStream.close();
counter++;
customLayout = request.getArg("android.cusom_layout" + counter, null);
}
} catch (IOException ex) {
throw new BuildException("Failed to generate layout XML file", ex);
}
String storeIds = request.getArg("android.store_ids", null);
if (storeIds != null) {
String[] sp = storeIds.split(";");
storeIds = "";
for (String s : sp) {
storeIds += " Display.getInstance().setProperty(\"" + s + "\", \"\" + " + s + ");\n";
}
} else {
storeIds = "";
}
String gcmSenderId = request.getArg("gcm.sender_id", null);
if (gcmSenderId != null) {
gcmSenderId = " Display.getInstance().setProperty(\"gcm.sender_id\", \"" + gcmSenderId + "\");\n";
} else {
if (googleServicesJson != null && googleServicesJson.exists()) {
try {
JSONParser parser = new JSONParser();
Map<String, Object> parsedJson = parser.parseJSON(new FileReader(googleServicesJson));
Map projectInfo = (Map) parsedJson.get("project_info");
gcmSenderId = (String) projectInfo.get("project_number");
if (gcmSenderId != null) {
gcmSenderId = " Display.getInstance().setProperty(\"gcm.sender_id\", \"" + gcmSenderId + "\");\n";
} else {
gcmSenderId = "";
}
} catch (IOException ex) {
throw new BuildException("Failed to parse the google services JSON file " + googleServicesJson);
}
} else {
gcmSenderId = "";
}
}
File manifestFile = new File(projectDir + "/src/main", "AndroidManifest.xml");
float version = 1.0f;
int intVersion = 1;
try {
version = Float.parseFloat(request.getVersion());
String vcOverride = request.getArg("android.versionCode", null);
if (vcOverride != null && vcOverride.length() > 0) {
intVersion = Integer.parseInt(vcOverride);
} else {
intVersion = Math.round(100 * version);
}
} catch (Throwable thrown) {
}
String locationServices = "<activity android:name=\"com.codename1.location.CodenameOneBackgroundLocationActivity\" android:theme=\"@android:style/Theme.NoDisplay\" />\n" + "<service android:name=\"com.codename1.location.BackgroundLocationHandler\" android:exported=\"false\" />\n" + "<service android:name=\"com.codename1.location.GeofenceHandler\" android:exported=\"false\" />\n";
String mediaService = "<service android:name=\"com.codename1.media.AudioService\" android:exported=\"false\" />";
String remoteControlService = "<service android:name=\"com.codename1.media.BackgroundAudioService\">\n" + " <intent-filter>\n" + " <action android:name=\"android.intent.action.MEDIA_BUTTON\" />\n" + " <action android:name=\"android.media.AUDIO_BECOMING_NOISY\" />\n" + " <action android:name=\"android.media.browse.MediaBrowserService\" />\n" + " </intent-filter>\n" + " </service>";
String mediabuttonReceiver = "<receiver android:name=\"" + xclass("android.support.v4.media.session.MediaButtonReceiver") + "\">\n" + " <intent-filter>\n" + " <action android:name=\"android.intent.action.MEDIA_BUTTON\" />\n" + " <action android:name=\"android.media.AUDIO_BECOMING_NOISY\" />\n" + " </intent-filter>\n" + " </receiver>";
if (!addRemoteControlService) {
remoteControlService = "";
mediabuttonReceiver = "";
}
String alarmRecevier = "<receiver android:name=\"com.codename1.impl.android.LocalNotificationPublisher\" ></receiver>\n";
String backgroundLocationReceiver = "<receiver android:name=\"com.codename1.location.BackgroundLocationBroadcastReceiver\" ></receiver>\n";
if (!playServicesLocation) {
backgroundLocationReceiver = "";
}
String backgroundFetchService = "<service android:name=\"com.codename1.impl.android.BackgroundFetchHandler\" android:exported=\"false\" />\n" + "<activity android:name=\"com.codename1.impl.android.CodenameOneBackgroundFetchActivity\" android:theme=\"@android:style/Theme.NoDisplay\" />\n";
if (foregroundServicePermission) {
permissions += permissionAdd(request, "\"android.permission.FOREGROUND_SERVICE\"", " <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\" />\n");
}
if (capturePermission) {
String andc = request.getArg("android.captureRecord", "enabled");
if (request.getArg("and.captureRecord", andc).equals("enabled")) {
permissions += permissionAdd(request, "\"android.hardware.camera\"", "<uses-feature android:name=\"android.hardware.camera\" android:required=\"false\" />\n") + permissionAdd(request, "RECORD_AUDIO", " <uses-permission android:name=\"android.permission.RECORD_AUDIO\" android:required=\"false\" />\n");
} else {
permissions += permissionAdd(request, "\"android.hardware.camera\"", "<uses-feature android:name=\"android.hardware.camera\" android:required=\"false\" />\n");
}
}
if (vibratePermission) {
permissions += permissionAdd(request, "VIBRATE", " <uses-permission android:name=\"android.permission.VIBRATE\" android:required=\"false\" />\n");
}
if (smsPermission) {
permissions += permissionAdd(request, "SEND_SMS", "<uses-permission android:name=\"android.permission.SEND_SMS\" android:required=\"false\" />\n");
}
if (gpsPermission) {
permissions += " <uses-feature android:name=\"android.hardware.location\" android:required=\"false\" />\n" + " <uses-feature android:name=\"android.hardware.location.gps\" android:required=\"false\" />\n" + permissionAdd(request, "ACCESS_FINE_LOCATION", " <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" android:required=\"false\" />\n") + permissionAdd(request, "ACCESS_COARSE_LOCATION", " <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" android:required=\"false\" />\n");
if (request.getArg("android.mockLocation", "true").equals("true")) {
permissions += permissionAdd(request, "ACCESS_MOCK_LOCATION", " <uses-permission android:name=\"android.permission.ACCESS_MOCK_LOCATION\" android:required=\"false\" />\n");
}
}
if (pushPermission && !useFCM) {
permissions += "<permission android:name=\"" + request.getPackageName() + ".permission.C2D_MESSAGE\" android:protectionLevel=\"signature\" />\n" + " <uses-permission android:name=\"" + request.getPackageName() + ".permission.C2D_MESSAGE\" />\n" + " <uses-permission android:name=\"com.google.android.c2dm.permission.RECEIVE\" />\n";
// + permissionAdd(request, "RECEIVE_BOOT_COMPLETED",
// " <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" android:required=\"false\" />\n");
}
if (contactsReadPermission) {
permissions += permissionAdd(request, "READ_CONTACTS", " <uses-permission android:name=\"android.permission.READ_CONTACTS\" android:required=\"false\" />\n");
}
if (contactsWritePermission) {
permissions += permissionAdd(request, "WRITE_CONTACTS", " <uses-permission android:name=\"android.permission.WRITE_CONTACTS\" android:required=\"false\" />\n");
}
if (accessWifiStatePermissions) {
permissions += permissionAdd(request, "ACCESS_WIFI_STATE", "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" android:required=\"false\" />\n");
}
if (browserBookmarksPermissions) {
permissions += "<uses-permission android:name=\"com.android.browser.permission.WRITE_HISTORY_BOOKMARKS\" android:required=\"false\"/>\n" + "<uses-permission android:name=\"com.android.browser.permission.READ_HISTORY_BOOKMARKS\" android:required=\"false\"/>\n";
}
if (launcherPermissions) {
permissions += "<uses-permission android:name=\"com.android.launcher.permission.INSTALL_SHORTCUT\"/>\n" + "<uses-permission android:name=\"com.android.launcher.permission.UNINSTALL_SHORTCUT\"/>\n" + "<uses-permission android:name=\"com.android.launcher.permission.READ_SETTINGS\"/>\n" + "<!--device specific permissions -->\n" + "<uses-permission android:name=\"com.htc.launcher.permission.READ_SETTINGS\"/>\n" + "<uses-permission android:name=\"com.motorola.launcher.permission.READ_SETTINGS\"/>\n" + "<uses-permission android:name=\"com.motorola.dlauncher.permission.READ_SETTINGS\"/>\n" + "<uses-permission android:name=\"com.fede.launcher.permission.READ_SETTINGS\"/>\n" + "<uses-permission android:name=\"com.lge.launcher.permission.READ_SETTINGS\"/>\n" + "<uses-permission android:name=\"org.adw.launcher.permission.READ_SETTINGS\"/>\n" + "<uses-permission android:name=\"com.motorola.launcher.permission.INSTALL_SHORTCUT\"/>\n" + "<uses-permission android:name=\"com.motorola.dlauncher.permission.INSTALL_SHORTCUT\"/>\n" + "<uses-permission android:name=\"com.lge.launcher.permission.INSTALL_SHORTCUT\"/>\n";
}
if (recordAudio) {
permissions += permissionAdd(request, "RECORD_AUDIO", "<uses-permission android:name=\"android.permission.RECORD_AUDIO\" android:required=\"false\" />\n");
}
if (wakeLock) {
permissions += permissionAdd(request, "WAKE_LOCK", "<uses-permission android:name=\"android.permission.WAKE_LOCK\" android:required=\"false\" />\n");
}
if (phonePermission) {
permissions += permissionAdd(request, "READ_PHONE_STATE", "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\" android:required=\"false\" />\n");
}
if (accessNetworkStatePermission) {
permissions += permissionAdd(request, "ACCESS_NETWORK_STATE", "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" android:required=\"false\" />\n");
}
if (recieveBootCompletedPermission) {
permissions += permissionAdd(request, "RECEIVE_BOOT_COMPLETED", "<uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" android:required=\"false\" />\n");
}
if (getAccountsPermission) {
permissions += permissionAdd(request, "GET_ACCOUNTS", "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\" android:required=\"false\" />\n");
}
if (credentialsPermission) {
permissions += permissionAdd(request, "USE_CREDENTIALS", "<uses-permission android:name=\"android.permission.USE_CREDENTIALS\" />\n");
}
if (backgroundLocationPermission && !xPermissions.contains("android.permission.ACCESS_BACKGROUND_LOCATION")) {
permissions += "<uses-permission android:name=\"android.permission.ACCESS_BACKGROUND_LOCATION\" android:required=\"false\" />\n";
}
String billingServiceData = "";
String activityBillingSource = "";
String consumable = "";
if (purchasePermissions) {
String k = request.getArg("android.licenseKey", null);
// if the android.licenseKey is not defined abort the build
if (k == null) {
throw new BuildException("android.licenseKey must be defined in the build hints, grab the key from the \"Monetization setup\" section in the android dev portal" + ", then paste the Base64-encoded RSA public key into the android.licenseKey build hint.\n\n");
}
String cons = request.getArg("android.nonconsumable", null);
if (cons != null) {
cons = cons.trim();
if (cons.contains(",")) {
StringTokenizer token = new StringTokenizer(cons, ",");
if (token.countTokens() > 0) {
try {
while (token.hasMoreElements()) {
String t = (String) token.nextToken();
t = t.trim();
consumable += "\"" + t + "\",";
}
consumable = consumable.substring(0, consumable.length() - 1);
} catch (Exception e) {
// the pattern is not valid
}
}
} else {
consumable = "\"" + cons + "\"";
}
}
permissions += " <uses-permission android:name=\"com.android.vending.BILLING\" android:required=\"false\" />\n";
activityBillingSource = " protected boolean isBillingEnabled() {\n" + " return true;\n" + " }\n\n" + " protected com.codename1.impl.android.IBillingSupport createBillingSupport() {\n" + " return new com.codename1.impl.android.BillingSupport(this);\n" + " }\n\n";
}
String sharedUserId = request.getArg("android.sharedUserId", "");
if (sharedUserId.length() > 0) {
sharedUserId = " android:sharedUserId=\"" + sharedUserId + "\"\n";
}
String sharedUserLabel = request.getArg("android.sharedUserLabel", "");
if (sharedUserLabel.length() > 0) {
sharedUserLabel = " android:sharedUserLabel=\"" + sharedUserLabel + "\"\n";
}
String basePermissions = " <uses-feature android:name=\"android.hardware.telephony\" android:required=\"" + telephonyRequired + "\" />\n" + " <uses-permission android:name=\"android.permission.INTERNET\" android:required=\"false\" />\n";
if (request.getArg("android.removeBasePermissions", "false").equals("true")) {
basePermissions = "";
}
String externalStoragePermission = " <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" android:required=\"false\" />\n";
if (request.getArg("android.blockExternalStoragePermission", "false").equals("true")) {
externalStoragePermission = "";
}
String xmlizedDisplayName = xmlize(request.getDisplayName());
String applicationAttr = request.getArg("android.xapplication_attr", "");
String allowBackup = " android:allowBackup=\"" + request.getArg("android.allowBackup", "true") + "\" ";
if (applicationAttr.contains("allowBackup")) {
allowBackup = "";
}
String applicationNode = " <application ";
if (!applicationAttr.contains("android:label")) {
applicationNode += " android:label=\"" + xmlizedDisplayName + "\" ";
}
if (!applicationAttr.contains("android:icon")) {
applicationNode += " android:icon=\"@drawable/icon\" ";
}
if (request.getArg("android.multidex", "false").equals("true") && Integer.parseInt(minSDK) < 21) {
debug("Setting Application node to MultiDexApplication because minSDK=" + minSDK + " < 21");
applicationNode += " android:name=\"" + xclass("android.support.multidex.MultiDexApplication") + "\" ";
}
applicationNode += applicationAttr;
applicationNode += allowBackup;
applicationNode += ">\n";
// Note: It is OK to reference android.support.FILE_PROVIDER_PATHS in android X still
// https://stackoverflow.com/a/57584508/2935174
String providerTag = "<provider\n" + " android:name=\"" + xclass("android.support.v4.content.FileProvider") + "\"\n" + " android:authorities=\"${applicationId}.provider\"\n" + " android:exported=\"false\"\n" + " android:grantUriPermissions=\"true\">\n" + " <meta-data\n" + " android:name=\"android.support.FILE_PROVIDER_PATHS\"\n" + " android:resource=\"@xml/file_paths\">\n" + " </meta-data>\n" + " </provider>";
if (!providerTag.isEmpty()) {
File filePathsFile = new File(xmlDir, "file_paths.xml");
String filePathsContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<paths xmlns:android=\"http://schemas.android.com/apk/res/android\">\n" + " <cache-path name=\"intent_files\" path=\"intent_files/\" />\n" + request.getArg("android.file_paths", " <files-path name=\"app_files\" path=\".\" />") + "</paths>";
try {
OutputStream filePathsStream = new FileOutputStream(filePathsFile);
filePathsStream.write(filePathsContent.getBytes());
filePathsStream.close();
} catch (IOException ex) {
throw new BuildException("Failed to write file path providers file", ex);
}
}
String pushManifestEntries = " <service android:name=\"PushNotificationService\">\n" + " <intent-filter>\n" + " <action android:name=\"" + request.getPackageName() + ".PushNotificationService\" />\n" + " </intent-filter>\n" + " </service>\n" + " <receiver android:name=\".PushReceiver\" android:permission=\"com.google.android.c2dm.permission.SEND\">\n" + " <intent-filter>\n" + " <action android:name=\"com.google.android.c2dm.intent.RECEIVE\" />\n" + " <category android:name=\"" + request.getPackageName() + "\" />\n" + " </intent-filter>\n" + " <intent-filter>\n" + " <action android:name=\"com.google.android.c2dm.intent.REGISTRATION\" />\n" + " <category android:name=\"" + request.getPackageName() + "\" />\n" + " </intent-filter>\n" + " </receiver>\n";
if (!pushPermission) {
pushManifestEntries = "";
} else if (useFCM) {
pushManifestEntries = "<service\n" + " android:name=\"com.codename1.impl.android.CN1FirebaseMessagingService\">\n" + " <intent-filter>\n" + " <action android:name=\"com.google.firebase.MESSAGING_EVENT\" />\n" + " </intent-filter>\n" + " </service>\n";
}
String launchMode = request.getArg("android.activity.launchMode", "singleTop");
String manifestSource = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " package=\"" + request.getPackageName() + "\"\n" + " android:versionCode=\"" + intVersion + "\"\n" + " android:versionName=\"" + request.getVersion() + "\"\n" + " xmlns:tools=\"http://schemas.android.com/tools\"\n" + sharedUserLabel + sharedUserId + " android:minSdkVersion=\"" + minSDK + "\"\n" + " android:installLocation=\"" + request.getArg("android.installLocation", "auto") + "\">\n" + " <uses-sdk android:minSdkVersion=\"" + minSDK + "\"" + targetSDKVersion + request.getArg("android.xmanifest", "") + " />\n" + " <supports-screens android:smallScreens=\"" + request.getArg("android.smallScreens", "true") + "\"\n" + " android:normalScreens=\"" + request.getArg("android.normalScreens", "true") + "\"\n" + " android:largeScreens=\"" + request.getArg("android.largeScreens", "true") + "\"\n" + " android:xlargeScreens=\"" + request.getArg("android.xlargeScreens", "true") + "\"\n" + request.getArg("android.supportScreens", "") + " android:anyDensity=\"" + request.getArg("android.anyDensity", "true") + "\" />\n" + applicationNode + providerTag + usesLibrary + googlePlayAdsMetaData + " <activity android:name=\"" + request.getMainClass() + "Stub\"\n" + request.getArg("android.xactivity", "") + " android:theme=\"@style/CustomTheme\"\n" + " android:configChanges=\"orientation|keyboardHidden|screenSize|smallestScreenSize|screenLayout\"\n" + " android:launchMode=\"" + launchMode + "\"\n" + " android:label=\"" + xmlizedDisplayName + "\">\n" + " <intent-filter>\n" + " <action android:name=\"android.intent.action.MAIN\" />\n" + " <category android:name=\"android.intent.category.LAUNCHER\" />\n" + " </intent-filter>\n" + request.getArg("android.xintent_filter", "") + " </activity>\n" + facebookActivityMetaData + facebookActivity + googlePlayAdsActivity + pushManifestEntries + billingServiceData + " " + request.getArg("android.xapplication", "") + mopubActivities + alarmRecevier + backgroundLocationReceiver + mediabuttonReceiver + backgroundFetchService + locationServices + mediaService + remoteControlService + " </application>\n" + " <uses-feature android:name=\"android.hardware.touchscreen\" android:required=\"false\" />\n" + basePermissions + externalStoragePermission + permissions + " " + xPermissions + " " + xQueries + "</manifest>\n";
try {
OutputStream manifestSourceStream = new FileOutputStream(manifestFile);
manifestSourceStream.write(manifestSource.getBytes());
manifestSourceStream.close();
} catch (IOException ex) {
throw new BuildException("Failed to write manifest file", ex);
}
debug("Generated manifest file: " + manifestSource);
String oncreate = request.getArg("android.onCreate", "");
String initStackSize = "";
String stackSize = request.getArg("android.stack_size", null);
if (stackSize != null) {
initStackSize = " com.codename1.impl.CodenameOneThread.STACK_FRAME_SIZE = " + stackSize + ";\n";
}
String licenseKey = request.getArg("android.licenseKey", null);
String androidLicenseKey = licenseKey;
if (androidLicenseKey != null) {
androidLicenseKey = "Display.getInstance().setProperty(\"android.licenseKey\", \"" + androidLicenseKey + "\");\n";
} else {
androidLicenseKey = "";
}
String useBackgroundPermissionSnippet = "";
if (backgroundLocationPermission) {
useBackgroundPermissionSnippet = "Display.getInstance().setProperty(\"android.requiresBackgroundLocationPermissionForAPI29\", \"true\");\n";
}
String streamMode = request.getArg("android.streamMode", null);
if (streamMode != null) {
if (streamMode.equals("music")) {
streamMode = " setVolumeControlStream(android.media.AudioManager.STREAM_MUSIC);\n";
} else {
streamMode = "";
}
} else {
streamMode = "";
}
String localNotificationCode = "";
localNotificationCode = "" + " if(i instanceof com.codename1.notifications.LocalNotificationCallback){\n" + " Intent intent = getIntent();\n" + " if(intent != null && intent.getExtras() != null && intent.getExtras().containsKey(\"LocalNotificationID\")){\n" + " String id = intent.getExtras().getString(\"LocalNotificationID\");\n" + " intent.removeExtra(\"LocalNotificationID\");\n" + " ((com.codename1.notifications.LocalNotificationCallback)i).localNotificationReceived(id);\n" + " }\n" + " }\n";
String reinitCode0 = "Display.init(this);\n";
reinitCode0 = "AndroidImplementation.startContext(this);\n";
String reinitCode = "Display.init(this);\n";
// We need to explicitly call initImpl() to setup the activity in case the
// last used context is a service, since Display.init() won't actually do
// a reinitialize in this case.
// We don't want to actually call deinitialize here because this is too heavy-handed,
// (if the service is running, this will create a new implementation and edt thread
// which will cause problems for existing background procresses.
// Doing it this way ensures that the EDT and implemenation objects will remain unchanged,
// but other things will be set up properly.
reinitCode = "AndroidImplementation.startContext(this);\n";
String waitingForPermissionsRequestOnStop = " if (isWaitingForPermissionResult()) {\n" + " return;\n" + " }\n";
String onStopCode = "protected void onStop() {\n" + " super.onStop();\n" + waitingForPermissionsRequestOnStop + " if(isWaitingForResult()){\n" + " return;\n" + " }\n" + " synchronized(LOCK) {\n" + " currentForm = null;\n" + " }\n" + " Display.getInstance().callSerially(new Runnable() { public void run() {i.stop();} });\n" + " running = false;\n" + " }\n\n";
// Added a bit of blocking to onStop() to prevent onDestroy() from being
// run before stop() is completed. This probably only shows up if the
// device is very low on RAM or is set to not keep activity due
// to developer options... but it is still better to finish onStop()
// before onDestroy() is run.
onStopCode = "protected void onStop() {\n";
onStopCode += " com.codename1.impl.android.AndroidImplementation.writeServiceProperties(this);\n";
onStopCode += " super.onStop();\n" + " if(isWaitingForResult()){\n" + " return;\n" + " }\n" + " synchronized(LOCK) {\n" + " currentForm = null;\n" + " }\n" + " final boolean[] complete = new boolean[1];\n" + "\n" + " Display.getInstance().callSerially(new Runnable() {\n" + " public void run() {\n" + " i.stop();\n" + " synchronized(complete) {\n" + " try {\n" + " complete[0] = true;\n" + " complete.notify();\n" + " } catch (Exception ex) {\n" + " }\n" + " }\n" + " }\n" + " });\n" + " while (!complete[0]) {\n" + " synchronized(complete) {\n" + " try {\n" + " complete.wait(500);\n" + " } catch (Exception ex){}\n" + " }\n" + " }\n" + " running = false;\n" + " }\n\n";
String onDestroyCode = " protected void onDestroy() {\n" + createOnDestroyCode(request) + " super.onDestroy();\n" + " Display.getInstance().callSerially(new Runnable() { public void run() {i.destroy(); Display.deinitialize();} });\n" + " running = false;\n" + " }\n";
onDestroyCode = "protected void onDestroy() {\n" + createOnDestroyCode(request) + " super.onDestroy();\n" + "\n" + " Display.getInstance().callSerially(new Runnable() { public void run() {i.destroy();} });\n" + " AndroidImplementation.stopContext(this);\n" + " running = false;\n" + " }";
File stubFileSourceFile = new File(stubFileSourceDir, request.getMainClass() + "Stub.java");
String consumableCode;
consumableCode = "public boolean isConsumable(String sku) {\n" + " boolean retVal = super.isConsumable(sku);\n" + " java.util.List l = new java.util.ArrayList();\n" + " java.util.Collections.addAll(l, consumable);\n" + " return retVal || l.contains(sku);\n" + "}\n";
String firstTimeStatic = "";
firstTimeStatic = " static";
String notificationChannelId = request.getArg("android.NotificationChannel.id", "cn1-channel");
String notificationChannelName = request.getArg("android.NotificationChannel.name", "Notifications");
String notificationChannelDescription = request.getArg("android.NotificationChannel.description", "Remote notifications");
// https://developer.android.com/reference/android/app/NotificationManager#IMPORTANCE_LOW
String notificationChannelImportance = request.getArg("android.NotificationChannel.importance", "2");
String notificationChannelEnableLights = request.getArg("android.NotificationChannel.enableLights", "true");
String notificationChannelLightColor = request.getArg("android.NotificationChannel.lightColor", "" + 0xffff0000);
String notificationChannelEnableVibration = request.getArg("android.NotificationChannel.enableVibration", "false");
String notificationChannelVibrationPattern = request.getArg("android.NotificationChannel.vibrationPattern", request.getArg("android.pushVibratePattern", null));
if (notificationChannelVibrationPattern != null) {
notificationChannelVibrationPattern = "\"" + notificationChannelVibrationPattern + "\"";
}
String pushInitDisplayProperties = "";
if (buildToolsVersionInt >= 26 && Integer.parseInt(targetNumber) >= 26) {
pushInitDisplayProperties = " Display.getInstance().setProperty(\"android.NotificationChannel.id\", \"" + notificationChannelId + "\");\n" + " Display.getInstance().setProperty(\"android.NotificationChannel.name\", \"" + notificationChannelName + "\");\n" + " Display.getInstance().setProperty(\"android.NotificationChannel.description\", \"" + notificationChannelDescription + "\");\n" + " Display.getInstance().setProperty(\"android.NotificationChannel.importance\", \"" + notificationChannelImportance + "\");\n" + " Display.getInstance().setProperty(\"android.NotificationChannel.enableLights\", \"" + notificationChannelEnableLights + "\");\n" + " Display.getInstance().setProperty(\"android.NotificationChannel.lightColor\", \"" + notificationChannelLightColor + "\");\n" + " Display.getInstance().setProperty(\"android.NotificationChannel.enableVibration\", \"" + notificationChannelEnableVibration + "\");\n" + " Display.getInstance().setProperty(\"android.NotificationChannel.vibrationPattern\", " + notificationChannelVibrationPattern + ");\n" + " try {\n" + " Display.getInstance().setProperty(\"android.NotificationChannel.soundUri\", android.media.RingtoneManager.getDefaultUri(android.media.RingtoneManager.TYPE_NOTIFICATION).toString());\n" + " } catch (Exception ex){}\n";
;
if (request.getArg("android.pushSound", null) != null) {
pushInitDisplayProperties += " try {\n" + " Display.getInstance().setProperty(\"android.NotificationChannel.soundUri\", \"android.resource://" + request.getPackageName() + "/raw/" + request.getArg("android.pushSound", null) + "\");\n" + " } catch (Exception ex){}\n";
}
}
String waitingForPermissionsRequest = " if (isWaitingForPermissionResult()) {\n" + " setWaitingForPermissionResult(false);\n" + " return;\n" + " }\n";
String stubSourceCode;
try {
stubSourceCode = "package " + request.getPackageName() + ";\n\n" + "import com.codename1.ui.*;\n" + "import android.os.Bundle;\n" + "import android.content.Intent;\n" + "import android.view.KeyEvent;\n" + "import com.codename1.system.*;\n" + "import com.codename1.impl.android.CodenameOneActivity;\n" + "import com.codename1.impl.android.AndroidImplementation;\n" + "import com.codename1.system.NativeLookup;\n" + "import com.codename1.push.*;\n" + "import com.codename1.ui.*;\n" + "import android.content.IntentFilter;\n" + additionalImports + "\n\n" + "public class " + request.getMainClass() + "Stub extends " + request.getArg("android.customActivity", "CodenameOneActivity") + "{\n";
stubSourceCode += decodeFunction();
stubSourceCode += " public static final String BUILD_KEY = \"" + xorEncode(getBuildKey()) + "\";\n" + " public static final String PACKAGE_NAME = \"" + request.getPackageName() + "\";\n" + " public static final String BUILT_BY_USER = \"" + xorEncode(request.getUserName()) + "\";\n" + " public static final String LICENSE_KEY = \"" + xorEncode(licenseKey) + "\";\n" + " String [] consumable = new String[]{" + consumable + "};\n" + " private static " + request.getMainClass() + "Stub stubInstance;\n" + " private static " + request.getMainClass() + " i;\n" + " private boolean running;\n" + " private" + firstTimeStatic + " boolean firstTime = true;\n" + " private Form currentForm;\n" + " private static final Object LOCK = new Object();\n" + additionalMembers + headphonesVars + " public static " + request.getMainClass() + " getAppInstance() {\n" + " return i;\n" + " }\n\n" + activityBillingSource + " protected Object getApp() {\n" + " return i;\n" + " }\n\n" + " public static " + request.getMainClass() + "Stub getInstance() {\n" + " return stubInstance;\n" + " }\n\n" + " public " + request.getMainClass() + "Stub() {\n" + " stubInstance = this;\n" + " }\n\n" + " public static boolean isRunning() {\n" + " return stubInstance != null && stubInstance.running;\n" + " }\n\n" + " public void onCreate(Bundle savedInstanceState) {\n" + " super.onCreate(savedInstanceState);\n" + facebookHashCode + facebookSupport + streamMode + registerNativeImplementationsAndCreateStubs(new URLClassLoader(new URL[] { codenameOneJar.toURI().toURL() }), srcDir, dummyClassesDir) + oncreate + "\n" + createOnCreateCode(request) + " }\n" + " protected void onResume() {\n" + " running = true;\n" + " super.onResume();\n" + waitingForPermissionsRequest + " if(!Display.isInitialized()) {\n" + initStackSize + headphonesOnResume + googlePlayAdViewCode + reinitCode0 + storeIds + gcmSenderId + " Display.getInstance().setProperty(\"build_key\", d(BUILD_KEY));\n" + " Display.getInstance().setProperty(\"package_name\", PACKAGE_NAME);\n" + " Display.getInstance().setProperty(\"built_by_user\", d(BUILT_BY_USER));\n" + useBackgroundPermissionSnippet + pushInitDisplayProperties + // + corporateServer
androidLicenseKey + // + " " + registerNativeImplementationsAndCreateStubs(srcDir, dummyClassesDir)
" " + createPostInitCode(request) + " }else{\n" + reinitCode + " }\n" + " if (i == null) {\n" + " i = new " + request.getMainClass() + "();\n" + " if(i instanceof PushCallback) {\n" + " com.codename1.impl.CodenameOneImplementation.setPushCallback((PushCallback)i);\n" + " }\n";
stubSourceCode += " if (i instanceof com.codename1.push.PushActionsProvider) {\n" + " try{AndroidImplementation.installNotificationActionCategories((com.codename1.push.PushActionsProvider)i);}catch(java.io.IOException ex){ex.printStackTrace();}\n" + " }\n";
} catch (Exception ex) {
throw new BuildException("Failed to generate stub source code", ex);
}
String fcmRegisterPushCode = "";
if (useFCM) {
fcmRegisterPushCode = "try {\n" + "\n" + " String token = com.google.firebase.iid.FirebaseInstanceId.getInstance().getToken();\n" + " if (token != null) {\n" + " com.codename1.io.Preferences.set(\"push_key\", \"cn1-fcm-\"+token);\n" + " if (i instanceof PushCallback) {\n" + " ((PushCallback)i).registeredForPush(\"cn1-fcm-\"+token);\n" + " }\n" + " } else {\n" + " java.util.Timer timer = new java.util.Timer();\n" + " timer.schedule(new java.util.TimerTask() {\n" + " public void run() {\n" + " runOnUiThread(new Runnable() {\n" + " public void run() {\n" + " String token = com.google.firebase.iid.FirebaseInstanceId.getInstance().getToken();\n" + " if (token != null) {\n" + " com.codename1.io.Preferences.set(\"push_key\", \"cn1-fcm-\" + token);\n" + " if (i instanceof PushCallback) {\n" + " ((PushCallback) i).registeredForPush(\"cn1-fcm-\" + token);\n" + " }\n" + " }\n" + " }\n" + " });\n" + " }\n" + " }, 2000);\n" + " }\n" + " } catch (Exception ex) {\n" + " if (i instanceof PushCallback) {\n" + " ((PushCallback)i).pushRegistrationError(\"Failed to register push: \"+ex.getMessage(), 0);\n" + " }\n" + " System.out.println(\"Failed to get fcm token.\");\n" + " ex.printStackTrace();\n" + " }";
}
try {
stubSourceCode += " }\n" + " if(i instanceof PushCallback) {\n" + " AndroidImplementation.firePendingPushes((PushCallback)i, this);\n" + " }\n" + localNotificationCode + " Display.getInstance().callSerially(new Runnable(){\n" + " boolean wasStopped = (currentForm == null);\n" + " Form currForm = currentForm;\n" + " public void run() {\n" + " Form displayForm = Display.getInstance().getCurrent();\n" + " " + request.getMainClass() + "Stub.this.run(displayForm == null ? currForm : displayForm, wasStopped);\n" + " }\n" + " });\n" + " synchronized(LOCK) {\n" + " currentForm = null;\n" + " }\n" + " }\n\n" + " protected void onPause() {\n" + " super.onPause();\n" + " synchronized(LOCK) {\n" + " currentForm = Display.getInstance().getCurrent();\n" + " }\n" + " running = false;\n" + " }\n\n" + " public void run(Form currentForm, boolean wasStopped) {\n" + " if(firstTime) {\n" + " firstTime = false;\n" + " i.init(this);\n" + fcmRegisterPushCode + " } else {\n" + " synchronized(LOCK) {\n" + " if(!wasStopped) {\n" + " if(currentForm instanceof Dialog) {\n" + " ((Dialog)currentForm).showModeless();\n" + " }else{\n" + " currentForm.show();\n" + " }\n" + " fireIntentResult();\n" + " setWaitingForResult(false);\n" + " return;\n" + " }\n" + " }\n" + " }\n" + createStartInvocation(request, "i") + " }\n" + onStopCode + onDestroyCode + " public boolean onKeyDown(int keyCode, KeyEvent event){\n" + " return super.onKeyDown(keyCode, event);\n" + " }\n" + " public String getBase64EncodedPublicKey() {\n" + " return d(LICENSE_KEY);\n" + " }\n" + consumableCode + "}\n";
} catch (Exception ex) {
throw new BuildException("Failure while generating stub source code", ex);
}
File androidImplDir = new File(srcDir, "com" + File.separator + "codename1" + File.separator + "impl" + File.separator + "android");
File stubUtilFile = new File(androidImplDir, "StubUtil.java");
if (stubUtilFile.exists()) {
try {
replaceInFile(stubUtilFile, "//!", "");
replaceInFile(stubUtilFile, "{{Stub}}", request.getPackageName() + "." + request.getMainClass() + "Stub");
} catch (IOException ex) {
throw new BuildException("Failed to update stub Util file", ex);
}
}
boolean backgroundPushHandling = "true".equals(request.getArg("android.background_push_handling", "false"));
if (!useFCM) {
File pushServiceFileSourceFile = new File(stubFileSourceDir, "PushNotificationService.java");
String pushServiceOnCreate = "";
if (buildToolsVersionInt >= 26 && Integer.parseInt(targetNumber) >= 26) {
pushServiceOnCreate = "\n @Override\n" + " public void onCreate() {\n" + " super.onCreate();\n" + " setProperty(\"android.NotificationChannel.id\", \"" + notificationChannelId + "\");\n" + " setProperty(\"android.NotificationChannel.name\", \"" + notificationChannelName + "\");\n" + " setProperty(\"android.NotificationChannel.description\", \"" + notificationChannelDescription + "\");\n" + " setProperty(\"android.NotificationChannel.importance\", \"" + notificationChannelImportance + "\");\n" + " setProperty(\"android.NotificationChannel.enableLights\", \"" + notificationChannelEnableLights + "\");\n" + " setProperty(\"android.NotificationChannel.lightColor\", \"" + notificationChannelLightColor + "\");\n" + " setProperty(\"android.NotificationChannel.enableVibration\", \"" + notificationChannelEnableVibration + "\");\n" + " setProperty(\"android.NotificationChannel.vibrationPattern\", " + notificationChannelVibrationPattern + ");\n" + " }\n\n";
}
// The runtime test to use to determine if we should call the push() method immediately
// upon receiving the notification. By default, we only send *immediately* if the app is
// in the foreground. You can use the android.background_push_handling to allow
// immediate handling in the background as well.
String handlePushImmediatelyCheck = request.getMainClass() + "Stub.isRunning()";
String stubIsRunningCheck = handlePushImmediatelyCheck;
if (backgroundPushHandling) {
handlePushImmediatelyCheck += " || Display.isInitialized()";
}
String pushServiceSourceCode = "package " + request.getPackageName() + ";\n\n" + "import com.codename1.ui.*;\n" + "import com.codename1.push.PushCallback;\n\n" + "public class PushNotificationService extends com.codename1.impl.android.PushNotificationService {\n" + " public PushCallback getPushCallbackInstance() {\n" + " if(" + handlePushImmediatelyCheck + ") {\n" + " " + request.getMainClass() + "Stub stub = " + request.getMainClass() + "Stub.getInstance();\n" + " final " + request.getMainClass() + " main = stub.getAppInstance();\n" + " if(main instanceof PushCallback) {\n" + " return (PushCallback)main;\n" + " }\n" + " }\n" + " return null;\n" + " }\n\n" + " public Class getStubClass() {\n" + " return " + request.getMainClass() + "Stub.class;\n" + " }\n" + pushServiceOnCreate + "}\n";
File pushFileSourceFile = new File(stubFileSourceDir, "PushReceiver.java");
String vibrateCode = "";
if (request.getArg("android.pushVibratePattern", null) != null) {
String pattern = request.getArg("android.pushVibratePattern", null);
pattern = pattern.trim();
StringTokenizer token = new StringTokenizer(pattern, ",");
if (token.countTokens() > 0) {
try {
while (token.hasMoreElements()) {
String t = (String) token.nextToken();
t = t.trim();
Long.parseLong(t);
}
vibrateCode = "mNotifyBuilder.setVibrate(new long[]{" + pattern + "});";
} catch (Exception e) {
// the pattern is not valid
}
}
}
String pushSound = "";
if (request.getArg("android.pushSound", null) != null) {
String soundPath = request.getArg("android.pushSound", null).toLowerCase();
pushSound = "mNotifyBuilder.setSound(android.net.Uri.parse(\"android.resource://" + request.getPackageName() + "/raw/" + soundPath + "\"));";
}
String pushReceiverSourceCode = "package " + request.getPackageName() + ";\n\n" + "import com.codename1.ui.*;\n\n" + "import android.os.Bundle;\n\n" + "import com.codename1.system.*;\n" + "import com.codename1.impl.android.CodenameOneActivity;\n\n" + "import com.codename1.impl.android.AndroidImplementation;\n\n" + "import com.codename1.system.NativeLookup;\n\n" + "import com.codename1.io.ConnectionRequest;\n\n" + "import com.codename1.io.Preferences;\n\n" + "import com.codename1.io.NetworkManager;\n\n" + "import com.codename1.push.PushCallback;\n\n" + "import java.io.InputStream;\n" + "import java.io.DataInputStream;\n" + "import java.io.IOException;\n" + "import android.app.Notification;\n" + "import android.app.NotificationManager;\n" + "import android.app.PendingIntent;\n" + "import android.content.BroadcastReceiver;\n" + "import android.content.Context;\n" + "import android.content.Intent;\n" + "import android.telephony.TelephonyManager;\n" + "import android.content.SharedPreferences.Editor;\n" + "import android.app.NotificationManager\n;" + "import android.app.Activity;\n" + "import com.codename1.impl.android.PushNotificationService;\n" + "import com.codename1.ui.*;\n" + "import android.graphics.Bitmap;\n" + "import android.graphics.drawable.BitmapDrawable;\n" + "import android.graphics.drawable.Drawable;\n" + "import " + xclass("android.support.v4.app.NotificationCompat") + ".Builder;\n" + "import " + xclass("android.support.v4.app.NotificationCompat") + ";\n" + "import android.media.RingtoneManager;\n" + "import android.net.Uri;\n\n" + "public class PushReceiver extends BroadcastReceiver {\n" + " public static final String C2DM_MESSAGE_TYPE_EXTRA = \"messageType\";\n" + " public static final String C2DM_MESSAGE_EXTRA = \"message\";\n" + " public static final String C2DM_MESSAGE_IMAGE = \"image\";\n" + " public static final String C2DM_MESSAGE_CATEGORY = \"category\";\n" + " public static final String BUILD_KEY = \"" + xorEncode(getBuildKey()) + "\"\n;" + " public static final String PACKAGE_NAME = \"" + request.getPackageName() + "\"\n;" + " public static final String BUILT_BY_USER = \"" + xorEncode(request.getUserName()) + "\"\n;" + " private static String KEY = \"c2dmPref\";\n" + " private static String REGISTRATION_KEY = \"registrationKey\";" + " private Context context;\n\n";
pushReceiverSourceCode += decodeFunction();
boolean includePushContent = true;
pushReceiverSourceCode += " @Override\n" + " public void onReceive(Context context, Intent intent) {\n" + " this.context = context;\n" + " if (intent.getAction().equals(\"com.google.android.c2dm.intent.REGISTRATION\")) {\n" + " handleRegistration(context, intent);\n" + " return;\n" + " }\n" + " if (intent.getAction().equals(\"com.google.android.c2dm.intent.RECEIVE\")) {\n" + " handleMessage(context, intent);\n" + " return;\n" + " }\n" + " if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {\n" + " if(!com.codename1.impl.android.AndroidImplementation.hasAndroidMarket(context)) {\n" + " PushNotificationService.startServiceIfRequired(" + request.getPackageName() + ".PushNotificationService.class, context);\n" + " }\n" + " return;\n" + " }\n" + " }\n\n" + " private void handleRegistration(Context context, Intent intent) {\n" + " final String registration = intent.getStringExtra(\"registration_id\");\n" + " System.out.println(\"Push handleRegistration() received: \" + registration);\n" + " " + request.getMainClass() + "Stub stub = " + request.getMainClass() + "Stub.getInstance();\n" + " if (intent.getStringExtra(\"error\") != null) {\n" + " final String error = intent.getStringExtra(\"error\");\n" + " System.out.println(\"Push handleRegistration() error: \" + error);\n" + " final " + request.getMainClass() + " main = stub.getAppInstance();\n" + " if(main instanceof PushCallback) {\n" + " Display.getInstance().callSerially(new Runnable() {\n" + " public void run() {\n" + " ((PushCallback)main).pushRegistrationError(error, 0);\n" + " }\n" + " });\n" + " }\n" + " } else if (intent.getStringExtra(\"unregistered\") != null) {\n // do something??? \n" + " System.out.println(\"Push deregistered!\");\n" + " } else if (registration != null) {\n" + " System.out.println(\"Push handleRegistration() Sending registration to server!\");\n" + " Editor editor = context.getSharedPreferences(KEY, Context.MODE_PRIVATE).edit();\n" + " editor.putString(REGISTRATION_KEY, registration);\n" + " Preferences.set(\"push_key\", registration);\n" + " editor.commit();\n" + " com.codename1.impl.android.AndroidImplementation.registerPushOnServer(registration, d(BUILT_BY_USER) + '/' + PACKAGE_NAME, (byte)1, \"\", \"" + request.getPackageName() + "\");\n" + " final " + request.getMainClass() + " main = stub.getAppInstance();\n" + " if(main instanceof PushCallback) {\n" + " Display.getInstance().callSerially(new Runnable() {\n" + " public void run() {\n" + " ((PushCallback)main).registeredForPush(registration);\n" + " }\n" + " });\n" + " }\n" + " }\n" + " }\n\n" + " private android.graphics.Bitmap getBitmapfromUrl(String imageUrl) {\n" + " try {\n" + " java.net.URL url = new java.net.URL(imageUrl);\n" + " java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();\n" + " connection.setDoInput(true);\n" + " connection.connect();\n" + " InputStream input = connection.getInputStream();\n" + " Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(input);\n" + " return bitmap;\n" + "\n" + " } catch (Exception e) {\n" + " // TODO Auto-generated catch block\n" + " e.printStackTrace();\n" + " return null;\n" + "\n" + " }\n" + " }\n\n" + " private void handleMessage(final Context context, Intent intent) {\n" + " final String messageType = intent.getExtras().getString(C2DM_MESSAGE_TYPE_EXTRA);\n" + " final String message = intent.getExtras().getString(C2DM_MESSAGE_EXTRA);\n" + " final String image = intent.getExtras().getString(C2DM_MESSAGE_IMAGE);\n" + " final String category = intent.getExtras().getString(C2DM_MESSAGE_CATEGORY);\n" + " System.out.println(\"Push message received: \" + message);\n" + " System.out.println(\"Push type: \" + messageType);\n" + " System.out.println(\"Is running: \" + " + request.getMainClass() + "Stub.isRunning());\n" + " if(" + handlePushImmediatelyCheck + ") {\n" + " " + request.getMainClass() + "Stub stub = " + request.getMainClass() + "Stub.getInstance();\n" + " final " + request.getMainClass() + " main = stub.getAppInstance();\n" + " if(main instanceof PushCallback) {\n" + " Display.getInstance().setProperty(\"pushType\", messageType);\n";
pushReceiverSourceCode += " Display.getInstance().callSerially(new Runnable() {\n" + " public void run() {\n";
if (includePushContent) {
pushReceiverSourceCode += " com.codename1.impl.android.AndroidImplementation.initPushContent(message, image, messageType, category, context);\n";
}
pushReceiverSourceCode += " if(messageType != null && (Integer.parseInt(messageType) == 3 || Integer.parseInt(messageType) == 6) ) {\n" + " String[] a = message.split(\";\");\n";
pushReceiverSourceCode += " ((PushCallback)main).push(a[0]);\n" + " ((PushCallback)main).push(a[1]);\n" + " return;\n" + " } else if (\"101\".equals(messageType)) {\n" + " ((PushCallback) main).push(message.substring(message.indexOf(\" \")+1));\n" + " return;\n" + " }\n";
pushReceiverSourceCode += " ((PushCallback)main).push(message);\n" + " }\n" + " });\n" + " }\n" + " }" + " if (!" + stubIsRunningCheck + ") {\n" + " ";
pushReceiverSourceCode += " com.codename1.impl.android.AndroidImplementation.appendNotification(messageType, message, image, category, context);\n";
pushReceiverSourceCode += " int badgeNumber = -1;\n" + " if (\"101\".equals(messageType)) {\n" + " badgeNumber = Integer.parseInt(message.substring(0, message.indexOf(\" \")));\n" + "\n" + " }" + "if(messageType == null || messageType.length() == 0 || Integer.parseInt(messageType) < 2 || messageType.equals(\"3\") || messageType.equals(\"4\") || messageType.equals(\"5\") || messageType.equals(\"6\") || messageType.equals(\"101\")) {\n" + " String actualMessage = message;\n" + " if (\"101\".equals(messageType)) {\n" + " actualMessage = message.substring(message.indexOf(\" \")+1);\n" + " }" + " String title = \"" + request.getDisplayName() + "\";\n" + " if(messageType != null && (Integer.parseInt(messageType) == 3 || Integer.parseInt(messageType) == 6)) {\n" + " String[] a = message.split(\";\");\n" + " actualMessage = a[0];\n" + " }\n" + " if (messageType != null && Integer.parseInt(messageType) == 4) {\n" + " String[] a = message.split(\";\");\n" + " title = a[0];\n" + " actualMessage = a[1];\n" + " }\n" + " NotificationManager nm = (NotificationManager)context.getSystemService(Activity.NOTIFICATION_SERVICE);\n" + " Intent newIntent = new Intent(context, " + request.getMainClass() + "Stub.class);\n" + " PendingIntent contentIntent = PendingIntent.getActivity(context, 0, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);\n" + " Drawable myIcon = context.getResources().getDrawable(R.drawable.icon);\n" + " Bitmap icon = ((BitmapDrawable) myIcon).getBitmap();\n" + " int notifyID = 1;\n" + " Builder mNotifyBuilder = new NotificationCompat.Builder(context)\n" + " .setContentTitle(title)\n" + " .setSmallIcon(R.drawable.ic_stat_notify)\n" + " .setLargeIcon(icon)\n" + " .setContentIntent(contentIntent)\n" + " .setAutoCancel(true)\n" + " .setWhen(System.currentTimeMillis())\n" + " .setTicker(actualMessage);\n" + vibrateCode + " if (messageType == null || (Integer.parseInt(messageType) != 5 && Integer.parseInt(messageType) != 6)) {\n" + " Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);\n" + " mNotifyBuilder.setSound(alarmSound);\n" + pushSound + " }\n" + " if(android.os.Build.VERSION.SDK_INT >= 21){\n" + " mNotifyBuilder.setCategory(\"Notification\");\n" + " }\n";
if (buildToolsVersionInt >= 26 && Integer.parseInt(targetNumber) >= 26) {
pushReceiverSourceCode += " com.codename1.impl.android.AndroidImplementation.setNotificationChannel(nm, mNotifyBuilder, context);\n";
}
pushReceiverSourceCode += " String[] messages = com.codename1.impl.android.AndroidImplementation.getPendingPush(messageType, context);\n" + " int numMessages = messages.length;\n" + " if (numMessages == 1) {\n" + " mNotifyBuilder.setContentText(messages[0]);\n" + " } else {\n" + " NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();\n" + " for (int i = 0; i < messages.length; i++) {\n" + " inboxStyle.addLine(messages[i]);\n" + " }\n" + " mNotifyBuilder.setStyle(inboxStyle);\n" + " }\n" + " if(android.os.Build.VERSION.SDK_INT >= 22) {\n" + " if (badgeNumber >= 0) {\n" + " mNotifyBuilder.setNumber(badgeNumber);\n" + " } else {\n" + " mNotifyBuilder.setNumber(numMessages);\n" + " }\n" + " }\n";
pushReceiverSourceCode += " if (category != null && numMessages == 1) {\n" + " try {\n" + " AndroidImplementation.addActionsToNotification(null, category, mNotifyBuilder, newIntent, context);\n" + " } catch (java.io.IOException ex) {\n" + " ex.printStackTrace();\n" + " }\n" + " }" + " if (image != null && numMessages == 1) {\n" + " final Builder fNotifyBuilder = mNotifyBuilder;\n" + " final int fNotifyID = notifyID;\n" + " final NotificationManager fnm = nm;\n" + " android.os.AsyncTask.execute(new Runnable() {\n" + " public void run() {\n" + " fNotifyBuilder.setStyle(new NotificationCompat.BigPictureStyle()\n" + " .bigPicture(getBitmapfromUrl(image)));/*Notification with Image*/\n" + " fnm.notify(fNotifyID, fNotifyBuilder.build());\n" + " }\n" + " });\n" + "\n" + " } else {\n" + " nm.notify(notifyID, mNotifyBuilder.build());\n" + " }\n";
pushReceiverSourceCode += " }\n" + " }\n" + " }\n" + "}\n";
if (pushPermission) {
try {
OutputStream pushSourceStream = new FileOutputStream(pushFileSourceFile);
pushSourceStream.write(pushReceiverSourceCode.getBytes());
pushSourceStream.close();
OutputStream pushServiceSourceStream = new FileOutputStream(pushServiceFileSourceFile);
pushServiceSourceStream.write(pushServiceSourceCode.getBytes());
pushServiceSourceStream.close();
} catch (IOException ex) {
throw new BuildException("Failed to generate push file", ex);
}
}
} else {
InputStream is = null;
OutputStream os = null;
debug("Generating FirebaseMessagingService...");
File fcmMessagingServiceFile = new File(androidImplDir, "CN1FirebaseMessagingService.java");
try {
String fireBaseMessagingServiceSourcePath = "CN1FirebaseMessagingService.javas";
fireBaseMessagingServiceSourcePath = "CN1FirebaseMessagingService7.javas";
is = getClass().getResourceAsStream(fireBaseMessagingServiceSourcePath);
os = new FileOutputStream(fcmMessagingServiceFile);
copy(is, os);
} catch (IOException ex) {
error("Failed to generate FirebaseMessagingService", ex);
throw new BuildException("Failed to generate FirebaseMessagingService", ex);
} finally {
if (is != null) {
try {
is.close();
} catch (Throwable t) {
}
}
if (os != null) {
try {
os.close();
} catch (Throwable t) {
}
}
}
try {
replaceInFile(fcmMessagingServiceFile, "{{DISPLAY_NAME}}", request.getDisplayName());
if (backgroundPushHandling) {
replaceInFile(fcmMessagingServiceFile, "allowBackgroundPush = false;", "allowBackgroundPush = true;");
}
} catch (IOException ex) {
throw new BuildException("Failed to update FCM messaging service with app details", ex);
}
}
try {
OutputStream stubSourceStream = new FileOutputStream(stubFileSourceFile);
stubSourceStream.write(stubSourceCode.getBytes());
stubSourceStream.close();
} catch (IOException ex) {
throw new BuildException("Failed to write stub source file", ex);
}
try {
File projectPropertiesFile = new File(projectDir, "project.properties");
Properties projectPropertiesObject = new Properties();
if (projectPropertiesFile.exists()) {
FileInputStream fi = new FileInputStream(projectPropertiesFile);
projectPropertiesObject.load(fi);
fi.close();
}
projectPropertiesObject.setProperty("proguard.config", "proguard.cfg");
if (request.getArg("android.enableProguard", "true").equals("false")) {
projectPropertiesObject.remove("proguard.config");
}
projectPropertiesObject.setProperty("dex.force.jumbo", "true");
FileOutputStream projectPropertiesOutputStream = new FileOutputStream(projectPropertiesFile);
projectPropertiesObject.store(projectPropertiesOutputStream, "Project properties for android build generated by Codename One");
projectPropertiesOutputStream.close();
} catch (IOException ex) {
throw new BuildException("Failed to write project properties", ex);
}
String dontObfuscate = "";
if (request.getArg("android.enableProguard", "true").equals("false")) {
dontObfuscate = "-dontobfuscate\n";
}
// workaround broken optimizer in proguard
String proguardConfigOverride = "-dontusemixedcaseclassnames\n" + "-dontskipnonpubliclibraryclasses\n" + "-dontpreverify\n" + "-verbose\n" + "-dontoptimize\n" + dontObfuscate + "\n" + "-dontwarn com.google.android.gms.**\n" + "-keep class com.codename1.impl.android.AndroidBrowserComponentCallback {\n" + "*;\n" + "}\n\n" + "-keep class com.codename1.impl.android.AndroidNativeUtil {\n" + "*;\n" + "}\n\n" + "-keepclassmembers class **.R$* {\n" + " public static <fields>;\n" + "}\n\n" + "-keep class **.R$*\n" + "-keep public class * extends android.app.Activity\n" + "-keep public class * extends android.app.Application\n" + "-keep public class * extends android.app.Service\n" + "-keep public class * extends android.content.BroadcastReceiver\n" + "-keep public class * extends android.content.ContentProvider\n" + "-keep public class * extends android.app.backup.BackupAgentHelper\n" + "-keep public class * extends android.preference.Preference\n" + "-keep public class com.android.vending.licensing.ILicensingService\n\n" + "-keep public class " + xclass("android.support.v4.app.RemoteInput") + " {*;}\n" + "-keep public class " + xclass("android.support.v4.app.RemoteInput") + "$Builder {*;}\n" + "-keep public class " + xclass("android.support.v4.app.NotificationCompat") + "$Builder {*;}\n" + "-keep public class " + xclass("android.support.v4.app.NotificationCompat") + "$Action {*;}\n" + "-keep public class " + xclass("android.support.v4.app.NotificationCompat") + "$Action$Builder {*;}\n" + "-keepclasseswithmembernames class * {\n" + " native <methods>;\n" + "}\n\n" + "-keepclasseswithmembers class * {\n" + " public <init>(android.content.Context, android.util.AttributeSet);\n" + "}\n\n" + "-keepclasseswithmembers class * {\n" + " public <init>(android.content.Context, android.util.AttributeSet, int);\n" + "}\n\n" + "-keepclassmembers class * extends android.app.Activity {\n" + " public void *(android.view.View);\n" + "}\n\n" + "-keepclassmembers enum * {\n" + " public static **[] values();\n" + " public static ** valueOf(java.lang.String);\n" + "}\n\n" + "-keep class * implements android.os.Parcelable {\n" + " public static final android.os.Parcelable$Creator *;\n" + "}\n" + "-keep class com.apperhand.common.** {\n" + "*;\n" + "}\n\n" + "-keep class com.apperhand.device.android.EULAActivity$EulaJsInterface {\n" + "*;\n" + "}\n\n" + "-keepclassmembers public class " + xclass("android.support.v4.app.NotificationCompat") + "$Builder {\n" + " public " + xclass("android.support.v4.app.NotificationCompat") + "$Builder setChannelId(java.lang.String);\n" + "}\n\n" + facebookProguard + " " + request.getArg("android.proguardKeep", "") + "\n" + googlePlayObfuscation + "-keep class com.google.mygson.**{\n" + "*;\n" + "}\n\n" + "-dontwarn android.support.**\n" + "-dontwarn androidx.**\n" + "-dontwarn com.google.ads.**\n" + "-keepattributes Exceptions, InnerClasses, Signature, Deprecated, SourceFile, LineNumberTable, *Annotation*, EnclosingMethod";
String gradleObfuscate = "";
File proguardConfigOverrideFile = new File(projectDir, "proguard.cfg");
proguardConfigOverrideFile.delete();
if (request.getArg("android.enableProguard", "true").equals("true")) {
try {
createFile(proguardConfigOverrideFile, proguardConfigOverride.getBytes());
} catch (IOException ex) {
throw new BuildException("Failed to create proguard config file", ex);
}
gradleObfuscate = " minifyEnabled true\n" + (request.getArg("android.shrinkResources", "false").equals("true") ? " shrinkResources true\n" : "") + " proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg'\n";
}
HashMap<String, String> env = new HashMap<String, String>();
env.put("ANDROID_HOME", androidSDKDir.getAbsolutePath());
env.put("SLAVE_AAPT_TIMEOUT", "20");
request.putArgument("var.android.playServicesVersion", playServicesVersion);
String additionalDependencies = request.getArg("gradleDependencies", "");
if (facebookSupported) {
minSDK = maxInt("15", minSDK);
String facebookSdkVersion = request.getArg("android.facebookSdkVersion", "4.39.0");
;
if (request.getArg("android.excludeBolts", "false").equals("true")) {
additionalDependencies += " compile ('com.facebook.android:facebook-android-sdk:" + facebookSdkVersion + "'){ exclude module: 'bolts-android' }\n";
} else {
additionalDependencies += " compile 'com.facebook.android:facebook-android-sdk:" + facebookSdkVersion + "'\n";
}
}
if (legacyGplayServicesMode) {
additionalDependencies += " compile 'com.google.android.gms:play-services:6.5.87'\n";
} else {
if (playServicesPlus) {
additionalDependencies += " compile 'com.google.android.gms:play-services-plus:" + playServicesVersion + "'\n";
}
if (playServicesAuth) {
additionalDependencies += " compile 'com.google.android.gms:play-services-auth:" + playServicesVersion + "'\n";
}
if (playServicesBase) {
additionalDependencies += " compile 'com.google.android.gms:play-services-base:" + playServicesVersion + "'\n";
}
if (playServicesIdentity) {
additionalDependencies += " compile 'com.google.android.gms:play-services-identity:" + playServicesVersion + "'\n";
}
if (playServicesIndexing) {
additionalDependencies += " compile 'com.google.android.gms:play-services-appindexing:" + playServicesVersion + "'\n";
}
if (playServicesInvite) {
additionalDependencies += " compile 'com.google.android.gms:play-services-appinvite:" + playServicesVersion + "'\n";
}
if (playServicesAnalytics) {
additionalDependencies += " compile 'com.google.android.gms:play-services-analytics:" + playServicesVersion + "'\n";
}
if (playServicesCast) {
additionalDependencies += " compile 'com.google.android.gms:play-services-cast:" + playServicesVersion + "'\n";
}
if (playServicesGcm) {
additionalDependencies += " compile 'com.google.android.gms:play-services-gcm:" + playServicesVersion + "'\n";
}
if (playServicesDrive) {
additionalDependencies += " compile 'com.google.android.gms:play-services-drive:" + playServicesVersion + "'\n";
}
if (playServicesFit) {
additionalDependencies += " compile 'com.google.android.gms:play-services-fitness:" + playServicesVersion + "'\n";
}
if (playServicesLocation) {
additionalDependencies += " compile 'com.google.android.gms:play-services-location:" + playServicesVersion + "'\n";
}
if (playServicesMaps) {
additionalDependencies += " compile 'com.google.android.gms:play-services-maps:" + playServicesVersion + "'\n";
}
if (playServicesAds) {
additionalDependencies += " compile 'com.google.android.gms:play-services-ads:" + playServicesVersion + "'\n";
}
if (playServicesVision) {
additionalDependencies += " compile 'com.google.android.gms:play-services-vision:" + playServicesVersion + "'\n";
}
if (playServicesNearBy) {
additionalDependencies += " compile 'com.google.android.gms:play-services-nearby:" + playServicesVersion + "'\n";
}
if (playServicesSafetyPanorama) {
additionalDependencies += " compile 'com.google.android.gms:play-services-panaroma:" + playServicesVersion + "'\n";
}
if (playServicesGames) {
additionalDependencies += " compile 'com.google.android.gms:play-services-games:" + playServicesVersion + "'\n";
}
if (playServicesSafetyNet) {
additionalDependencies += " compile 'com.google.android.gms:play-services-safenet:" + playServicesVersion + "'\n";
}
if (playServicesWallet) {
additionalDependencies += " compile 'com.google.android.gms:play-services-wallet:" + playServicesVersion + "'\n";
}
if (playServicesWear) {
additionalDependencies += " compile 'com.google.android.gms:play-services-wearable:" + playServicesVersion + "'\n";
}
}
if (purchasePermissions) {
additionalDependencies += " implementation 'com.android.billingclient:billing:4.0.0'\n";
}
String useLegacyApache = "";
if (request.getArg("android.apacheLegacy", "false").equals("true")) {
useLegacyApache = " useLibrary 'org.apache.http.legacy'\n";
}
String multidex = "";
if (request.getArg("android.multidex", "false").equals("true")) {
multidex = " multiDexEnabled true\n";
if (Integer.parseInt(minSDK) < 21) {
if (useAndroidX) {
if (!additionalDependencies.contains("androidx.multidex:multidex") && !request.getArg("android.gradleDep", "").contains("androidx.multidex:multidex")) {
additionalDependencies += " implementation 'androidx.multidex:multidex:1.0.3'\n";
}
} else {
if (!additionalDependencies.contains("com.android.support:multidex") && !request.getArg("android.gradleDep", "").contains("com.android.support:multidex")) {
additionalDependencies += " implementation 'com.android.support:multidex:1.0.3'\n";
}
}
}
}
String gradleDependency = "classpath 'com.android.tools.build:gradle:1.3.1'\n";
if (gradleVersionInt < 3) {
gradleDependency = "classpath 'com.android.tools.build:gradle:2.1.2'\n";
} else {
if (gradleVersionInt < 6) {
if (useAndroidX) {
gradleDependency = "classpath 'com.android.tools.build:gradle:3.2.0'\n";
} else {
gradleDependency = "classpath 'com.android.tools.build:gradle:3.0.1'\n";
}
} else {
gradleDependency = "classpath 'com.android.tools.build:gradle:4.1.1'\n";
}
}
gradleDependency += request.getArg("android.topDependency", "");
String compileSdkVersion = "'android-21'";
String quotedBuildToolsVersion = "'23.0.1'";
compileSdkVersion = "'android-" + request.getArg("android.sdkVersion", "23") + "'";
quotedBuildToolsVersion = "'" + buildToolsVersion + "'";
String java8P2 = "";
if (request.getArg("android.java8", "false").equals("true")) {
java8P2 = " compileOptions {\n" + " sourceCompatibility JavaVersion.VERSION_1_8\n" + " targetCompatibility JavaVersion.VERSION_1_8\n" + " }\n";
}
String mavenCentral = "";
if (request.getArg("android.includeMavenCentral", "false").equals("true")) {
mavenCentral = " mavenCentral()\n";
}
String jcenter = " jcenter()\n";
String injectRepo = request.getArg("android.repositories", "");
if (injectRepo.length() > 0) {
String[] repos = injectRepo.split(";");
injectRepo = "";
for (String s : repos) {
injectRepo += " " + s + "\n";
}
}
Properties gradlePropertiesObject = new Properties();
File gradlePropertiesFile = new File(projectDir, "gradle.properties");
if (gradlePropertiesFile.exists()) {
try {
FileInputStream fi = new FileInputStream(gradlePropertiesFile);
gradlePropertiesObject.load(fi);
fi.close();
} catch (IOException ex) {
throw new BuildException("Failed to load gradle properties from properties file " + gradlePropertiesFile, ex);
}
}
String supportV4Default = " compile 'com.android.support:support-v4:23.+'";
compileSdkVersion = maxPlatformVersion;
String supportLibVersion = maxPlatformVersion;
if (buildToolsVersion.startsWith("28")) {
compileSdkVersion = "28";
supportLibVersion = "28";
}
if (buildToolsVersion.startsWith("29")) {
compileSdkVersion = "29";
supportLibVersion = "28";
}
jcenter = " google()\n" + " jcenter()\n" + " mavenLocal()\n" + " mavenCentral()\n";
injectRepo += " google()\n" + " mavenLocal()\n" + " mavenCentral()\n";
if (!androidAppBundle && gradleVersionInt < 6 && buildToolsVersionInt < 30) {
gradlePropertiesObject.put("android.enableAapt2", "false");
}
if (!useAndroidX) {
supportV4Default = " compile 'com.android.support:support-v4:" + supportLibVersion + ".+'\n implementation 'com.android.support:appcompat-v7:" + supportLibVersion + ".+'\n";
} else {
supportV4Default = " implementation 'androidx.legacy:legacy-support-v4:1.0.0'\n implementation 'androidx.appcompat:appcompat:1.0.0'\n";
}
String compile = "compile";
if (useAndroidX) {
compile = "implementation";
}
String gradleProps = "apply plugin: 'com.android.application'\n" + request.getArg("android.gradlePlugin", "") + "\n" + "buildscript {\n" + " repositories {\n" + jcenter + injectRepo + " }\n" + " dependencies {\n" + gradleDependency + " }\n" + "}\n" + "\n" + "android {\n" + request.getArg("android.gradle.androidx", "") + "\n" + " compileSdkVersion " + compileSdkVersion + "\n" + " buildToolsVersion " + quotedBuildToolsVersion + "\n" + useLegacyApache + "\n" + " dexOptions {\n" + " preDexLibraries = false\n" + " incremental false\n" + " jumboMode = true\n" + " javaMaxHeapSize \"3g\"\n" + " }\n" + " defaultConfig {\n" + " applicationId \"" + request.getPackageName() + "\"\n" + " minSdkVersion " + minSDK + "\n" + " targetSdkVersion " + targetNumber + "\n" + " versionCode " + intVersion + "\n" + " versionName \"" + version + "\"\n" + multidex + request.getArg("android.xgradle_default_config", "") + " }\n" + java8P2 + " sourceSets {\n" + " main {\n" + " aidl.srcDirs = ['src/main/java']\n" + " }\n" + " }\n" + "\n" + " lintOptions {\n" + " lintOptions {\n" + " checkReleaseBuilds false\n" + " abortOnError false\n" + " }\n" + " }\n" + " signingConfigs {\n" + " release {\n" + " storeFile file(\"keyStore\")\n" + " storePassword \"" + escape(request.getCertificatePassword(), "$\"") + "\"\n" + " keyAlias \"" + escape(request.getKeystoreAlias(), "$\"") + "\"\n" + " keyPassword \"" + escape(request.getCertificatePassword(), "$\"") + "\"\n" + " }\n" + " }\n" + " buildTypes {\n" + " release {\n" + gradleObfuscate + " signingConfig signingConfigs.release\n" + " }\n" + ((request.getCertificate() != null) ? (" debug {\n" + " signingConfig signingConfigs.release\n" + " }\n") : "") + " }\n" + "}\n" + "\n" + "repositories {\n" + " google()\n" + " jcenter()\n" + injectRepo + " flatDir{\n" + " dirs 'libs'\n" + " }\n" + mavenCentral + "}\n" + "\n" + "dependencies {\n" + " " + compile + " fileTree(dir: 'libs', include: ['*.jar'])\n" + request.getArg("android.supportv4Dep", supportV4Default) + "\n" + addNewlineIfMissing(additionalDependencies) + addNewlineIfMissing(request.getArg("android.gradleDep", "")) + addNewlineIfMissing(aarDependencies) + "}\n" + request.getArg("android.xgradle", "");
debug("Gradle File start\n-------\n");
debug(gradleProps);
debug("-------\nGradle File end \n");
File gradleFile = new File(projectDir, "build.gradle");
try {
OutputStream gradleStream = new FileOutputStream(gradleFile);
gradleStream.write(gradleProps.getBytes());
gradleStream.close();
} catch (IOException ex) {
throw new BuildException("Failed to write gradle properties to " + gradleFile, ex);
}
File settingsGradle = new File(studioProjectDir, "settings.gradle");
try {
replaceInFile(settingsGradle, "My Application2", request.getDisplayName());
} catch (Exception ex) {
throw new BuildException("Failed to update settingsGradle with display name", ex);
}
gradlePropertiesObject.setProperty("org.gradle.daemon", "true");
if (request.getArg("android.forceJava8Builder", "false").equals("true")) {
gradlePropertiesObject.setProperty("org.gradle.java.home", System.getProperty("java.home"));
}
gradlePropertiesObject.setProperty("org.gradle.jvmargs", "-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8");
if (useAndroidX) {
gradlePropertiesObject.setProperty("android.useAndroidX", "true");
gradlePropertiesObject.setProperty("android.enableJetifier", "true");
}
try {
FileOutputStream antPropertiesOutputStream = new FileOutputStream(gradlePropertiesFile);
gradlePropertiesObject.store(antPropertiesOutputStream, "Gradle properties for android build generated by Codename One");
antPropertiesOutputStream.close();
} catch (IOException ex) {
throw new BuildException("Failed to output gradle properties file " + gradlePropertiesFile);
}
try {
migrateSourcesToAndroidX(projectDir);
} catch (Exception ex) {
throw new BuildException("Failed to migrate sources to AndroidX", ex);
}
if (request.getCertificate() != null) {
try {
createFile(new File(projectDir, "keyStore"), request.getCertificate());
} catch (IOException ex) {
throw new BuildException("Failed to create keyStore file", ex);
}
}
return true;
}
use of com.codename1.rad.ui.UI in project CodenameOne by codenameone.
the class EditableResources method saveXMLFile.
private void saveXMLFile(File xml, File resourcesDir) throws IOException {
// disable override for the duration of the save so stuff from the override doesn't
// get into the main resource file
File overrideFileBackup = overrideFile;
EditableResources overrideResourceBackup = overrideResource;
overrideResource = null;
overrideFile = null;
try {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(xml), "UTF-8"));
String[] resourceNames = getResourceNames();
Arrays.sort(resourceNames, String.CASE_INSENSITIVE_ORDER);
bw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
bw.write("<resource majorVersion=\"" + MAJOR_VERSION + "\" minorVersion=\"" + MINOR_VERSION + "\" useXmlUI=\"" + xmlUI + "\">\n");
for (int iter = 0; iter < resourceNames.length; iter++) {
String xResourceName = xmlize(resourceNames[iter]);
// write the magic number
byte magic = getResourceType(resourceNames[iter]);
switch(magic) {
case MAGIC_TIMELINE:
case MAGIC_ANIMATION_LEGACY:
case MAGIC_IMAGE_LEGACY:
case MAGIC_INDEXED_IMAGE_LEGACY:
magic = MAGIC_IMAGE;
break;
case MAGIC_THEME_LEGACY:
magic = MAGIC_THEME;
break;
case MAGIC_FONT_LEGACY:
magic = MAGIC_FONT;
break;
}
switch(magic) {
case MAGIC_IMAGE:
Object o = getResourceObject(resourceNames[iter]);
if (!(o instanceof MultiImage)) {
o = null;
}
bw.write(" <image name=\"" + xResourceName + "\" ");
com.codename1.ui.Image image = getImage(resourceNames[iter]);
MultiImage mi = (MultiImage) o;
int rType = getImageType(image, mi);
switch(rType) {
// PNG file
case 0xf1:
// JPEG File
case 0xf2:
if (image instanceof EncodedImage) {
byte[] data = ((EncodedImage) image).getImageData();
writeToFile(data, new File(resourcesDir, normalizeFileName(resourceNames[iter])));
} else {
FileOutputStream fo = new FileOutputStream(new File(resourcesDir, normalizeFileName(resourceNames[iter])));
BufferedImage buffer = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
buffer.setRGB(0, 0, image.getWidth(), image.getHeight(), image.getRGB(), 0, image.getWidth());
ImageIO.write(buffer, "png", fo);
fo.close();
}
break;
// SVG
case 0xf5:
// multiimage with SVG
case 0xf7:
SVG s = (SVG) image.getSVGDocument();
writeToFile(s.getSvgData(), new File(resourcesDir, normalizeFileName(resourceNames[iter])));
if (s.getBaseURL() != null && s.getBaseURL().length() > 0) {
bw.write("baseUrl=\"" + s.getBaseURL() + "\" ");
}
bw.write("type=\"svg\" ");
break;
case 0xF6:
File multiImageDir = new File(resourcesDir, normalizeFileName(resourceNames[iter]));
multiImageDir.mkdirs();
for (int imageIter = 0; imageIter < mi.getDpi().length; imageIter++) {
File f = null;
switch(mi.getDpi()[imageIter]) {
case Display.DENSITY_4K:
f = new File(multiImageDir, "4k.png");
break;
case Display.DENSITY_2HD:
f = new File(multiImageDir, "2hd.png");
break;
case Display.DENSITY_560:
f = new File(multiImageDir, "560.png");
break;
case Display.DENSITY_HD:
f = new File(multiImageDir, "hd.png");
break;
case Display.DENSITY_VERY_HIGH:
f = new File(multiImageDir, "veryhigh.png");
break;
case Display.DENSITY_HIGH:
f = new File(multiImageDir, "high.png");
break;
case Display.DENSITY_MEDIUM:
f = new File(multiImageDir, "medium.png");
break;
case Display.DENSITY_LOW:
f = new File(multiImageDir, "low.png");
break;
case Display.DENSITY_VERY_LOW:
f = new File(multiImageDir, "verylow.png");
break;
}
writeToFile(mi.getInternalImages()[imageIter].getImageData(), f);
}
bw.write("type=\"multi\" ");
break;
// Timeline
case MAGIC_TIMELINE:
File timeline = new File(resourcesDir, normalizeFileName(resourceNames[iter]));
DataOutputStream timelineOut = new DataOutputStream(new FileOutputStream(timeline));
writeTimeline(timelineOut, (Timeline) image);
timelineOut.close();
bw.write("type=\"timeline\" ");
break;
// Fail this is the wrong data type
default:
throw new IOException("Illegal type while creating image: " + Integer.toHexString(rType));
}
bw.write(" />\n");
continue;
case MAGIC_THEME:
Hashtable<String, Object> theme = getTheme(resourceNames[iter]);
theme.remove("name");
bw.write(" <theme name=\"" + xResourceName + "\">\n");
ArrayList<String> setOfKeys = new ArrayList<String>(theme.keySet());
Collections.sort(setOfKeys);
for (String key : setOfKeys) {
if (key.startsWith("@")) {
if (key.endsWith("Image")) {
bw.write(" <val key=\"" + key + "\" value=\"" + findId(theme.get(key), true) + "\" />\n");
} else {
bw.write(" <val key=\"" + key + "\" value=\"" + theme.get(key) + "\" />\n");
}
continue;
}
// if this is a simple numeric value
if (key.endsWith("Color")) {
bw.write(" <val key=\"" + key + "\" value=\"" + theme.get(key) + "\" />\n");
continue;
}
if (key.endsWith("align") || key.endsWith("textDecoration")) {
bw.write(" <val key=\"" + key + "\" value=\"" + ((Number) theme.get(key)).shortValue() + "\" />\n");
continue;
}
// if this is a short numeric value
if (key.endsWith("transparency")) {
bw.write(" <val key=\"" + key + "\" value=\"" + theme.get(key) + "\" />\n");
continue;
}
if (key.endsWith("opacity")) {
bw.write(" <val key=\"" + key + "\" value=\"" + theme.get(key) + "\" />\n");
continue;
}
// if this is a padding or margin then we will have the 4 values as bytes
if (key.endsWith("padding") || key.endsWith("margin")) {
bw.write(" <val key=\"" + key + "\" value=\"" + theme.get(key) + "\" />\n");
continue;
}
// padding and or margin type
if (key.endsWith("Unit")) {
byte[] b = (byte[]) theme.get(key);
bw.write(" <val key=\"" + key + "\" value=\"" + b[0] + "," + b[1] + "," + b[2] + "," + b[3] + "\" />\n");
continue;
}
if (key.endsWith("border")) {
Border border = (Border) theme.get(key);
if (border instanceof RoundBorder) {
RoundBorder rb = (RoundBorder) border;
bw.write(" <border key=\"" + key + "\" type=\"round\" " + "roundBorderColor=\"" + rb.getColor() + "\" " + "opacity=\"" + rb.getOpacity() + "\" " + "strokeColor=\"" + rb.getStrokeColor() + "\" " + "strokeOpacity=\"" + rb.getStrokeOpacity() + "\" " + "strokeThickness=\"" + rb.getStrokeThickness() + "\" " + "strokeMM=\"" + rb.isStrokeMM() + "\" " + "shadowSpread=\"" + rb.getShadowSpread() + "\" " + "shadowOpacity=\"" + rb.getShadowOpacity() + "\" " + "shadowX=\"" + rb.getShadowX() + "\" " + "shadowY=\"" + rb.getShadowY() + "\" " + "shadowBlur=\"" + rb.getShadowBlur() + "\" " + "shadowMM=\"" + rb.isShadowMM() + "\" " + "rectangle=\"" + rb.isRectangle() + "\" />\n");
continue;
}
if (border instanceof CSSBorder) {
bw.write(" <border key=\"" + key + "\" type=\"css\" " + "css=\"" + encodeXML(((CSSBorder) border).toCSSString()) + "\"/>\n");
continue;
}
if (border instanceof RoundRectBorder) {
RoundRectBorder rb = (RoundRectBorder) border;
bw.write(" <border key=\"" + key + "\" type=\"roundRect\" " + "strokeColor=\"" + rb.getStrokeColor() + "\" " + "strokeOpacity=\"" + rb.getStrokeOpacity() + "\" " + "strokeThickness=\"" + rb.getStrokeThickness() + "\" " + "strokeMM=\"" + rb.isStrokeMM() + "\" " + "shadowSpread=\"" + rb.getShadowSpread() + "\" " + "shadowOpacity=\"" + rb.getShadowOpacity() + "\" " + "shadowX=\"" + rb.getShadowX() + "\" " + "shadowY=\"" + rb.getShadowY() + "\" " + "shadowBlur=\"" + rb.getShadowBlur() + "\" " + "topOnlyMode=\"" + rb.isTopOnlyMode() + "\" " + "bottomOnlyMode=\"" + rb.isBottomOnlyMode() + "\" " + "cornerRadius=\"" + rb.getCornerRadius() + "\" " + "bezierCorners=\"" + rb.isBezierCorners() + "\" />\n");
continue;
}
int type = Accessor.getType(border);
switch(type) {
case BORDER_TYPE_EMPTY:
bw.write(" <border key=\"" + key + "\" type=\"empty\" />\n");
continue;
case BORDER_TYPE_LINE:
// use theme colors?
if (Accessor.isThemeColors(border)) {
bw.write(" <border key=\"" + key + "\" type=\"line\" millimeters=\"" + Accessor.isMillimeters(border) + "\" thickness=\"" + Accessor.getThickness(border) + "\" />\n");
} else {
bw.write(" <border key=\"" + key + "\" type=\"line\" millimeters=\"" + Accessor.isMillimeters(border) + "\" thickness=\"" + Accessor.getThickness(border) + "\" color=\"" + Accessor.getColorA(border) + "\" />\n");
}
continue;
case BORDER_TYPE_UNDERLINE:
// use theme colors?
if (Accessor.isThemeColors(border)) {
bw.write(" <border key=\"" + key + "\" type=\"underline\" millimeters=\"" + Accessor.isMillimeters(border) + "\" thickness=\"" + Accessor.getThickness(border) + "\" />\n");
} else {
bw.write(" <border key=\"" + key + "\" type=\"underline\" millimeters=\"" + Accessor.isMillimeters(border) + "\" thickness=\"" + Accessor.getThickness(border) + "\" color=\"" + Accessor.getColorA(border) + "\" />\n");
}
continue;
case BORDER_TYPE_ROUNDED:
if (Accessor.isThemeColors(border)) {
bw.write(" <border key=\"" + key + "\" type=\"rounded\" " + "thickness=\"" + Accessor.getThickness(border) + "\" arcW=\"" + Accessor.getArcWidth(border) + "\" arcH=\"" + Accessor.getArcHeight(border) + "\" />\n");
} else {
bw.write(" <border key=\"" + key + "\" type=\"rounded\" " + "thickness=\"" + Accessor.getThickness(border) + "\" arcW=\"" + Accessor.getArcWidth(border) + "\" arcH=\"" + Accessor.getArcHeight(border) + "\" color=\"" + Accessor.getColorA(border) + "\" />\n");
}
continue;
case BORDER_TYPE_ETCHED_RAISED:
// use theme colors?
if (Accessor.isThemeColors(border)) {
bw.write(" <border key=\"" + key + "\" type=\"etchedRaised\" " + "thickness=\"" + Accessor.getThickness(border) + "\" />\n");
} else {
bw.write(" <border key=\"" + key + "\" type=\"etchedRaised\" " + "thickness=\"" + Accessor.getThickness(border) + "\" color=\"" + Accessor.getColorA(border) + "\" colorB=\"" + Accessor.getColorB(border) + "\" />\n");
}
continue;
case BORDER_TYPE_ETCHED_LOWERED:
// use theme colors?
if (Accessor.isThemeColors(border)) {
bw.write(" <border key=\"" + key + "\" type=\"etchedLowered\" " + "thickness=\"" + Accessor.getThickness(border) + "\" />\n");
} else {
bw.write(" <border key=\"" + key + "\" type=\"etchedLowered\" " + "thickness=\"" + Accessor.getThickness(border) + "\" color=\"" + Accessor.getColorA(border) + "\" colorB=\"" + Accessor.getColorB(border) + "\" />\n");
}
continue;
case BORDER_TYPE_BEVEL_LOWERED:
// use theme colors?
if (Accessor.isThemeColors(border)) {
bw.write(" <border key=\"" + key + "\" type=\"bevelLowered\" " + "thickness=\"" + Accessor.getThickness(border) + "\" />\n");
} else {
bw.write(" <border key=\"" + key + "\" type=\"bevelLowered\" " + "thickness=\"" + Accessor.getThickness(border) + "\" color=\"" + Accessor.getColorA(border) + "\" colorB=\"" + Accessor.getColorB(border) + "\" colorC=\"" + Accessor.getColorC(border) + "\" colorD=\"" + Accessor.getColorD(border) + "\" />\n");
}
continue;
case BORDER_TYPE_BEVEL_RAISED:
if (Accessor.isThemeColors(border)) {
bw.write(" <border key=\"" + key + "\" type=\"bevelRaised\" " + "thickness=\"" + Accessor.getThickness(border) + "\" />\n");
} else {
bw.write(" <border key=\"" + key + "\" type=\"bevelRaised\" " + "thickness=\"" + Accessor.getThickness(border) + "\" color=\"" + Accessor.getColorA(border) + "\" colorB=\"" + Accessor.getColorB(border) + "\" colorC=\"" + Accessor.getColorC(border) + "\" colorD=\"" + Accessor.getColorD(border) + "\" />\n");
}
continue;
// case BORDER_TYPE_IMAGE_SCALED:
case BORDER_TYPE_IMAGE:
{
Image[] images = Accessor.getImages(border);
int resourceCount = 0;
for (int counter = 0; counter < images.length; counter++) {
if (images[counter] != null && findId(images[counter], true) != null) {
resourceCount++;
}
}
if (resourceCount != 2 && resourceCount != 3 && resourceCount != 8 && resourceCount != 9) {
System.out.println("Odd resource count for image border: " + resourceCount);
resourceCount = 2;
}
switch(resourceCount) {
case 2:
bw.write(" <border key=\"" + key + "\" type=\"image\" " + "i1=\"" + findId(images[0], true) + "\" " + "i2=\"" + findId(images[4], true) + "\" />\n");
break;
case 3:
bw.write(" <border key=\"" + key + "\" type=\"image\" " + "i1=\"" + findId(images[0], true) + "\" " + "i2=\"" + findId(images[4], true) + "\" " + "i3=\"" + findId(images[8], true) + "\" />\n");
break;
case 8:
bw.write(" <border key=\"" + key + "\" type=\"image\" " + "i1=\"" + findId(images[0], true) + "\" " + "i2=\"" + findId(images[1], true) + "\" " + "i3=\"" + findId(images[2], true) + "\" " + "i4=\"" + findId(images[3], true) + "\" " + "i5=\"" + findId(images[4], true) + "\" " + "i6=\"" + findId(images[5], true) + "\" " + "i7=\"" + findId(images[6], true) + "\" " + "i8=\"" + findId(images[7], true) + "\" />\n");
break;
case 9:
bw.write(" <border key=\"" + key + "\" type=\"image\" " + "i1=\"" + findId(images[0], true) + "\" " + "i2=\"" + findId(images[1], true) + "\" " + "i3=\"" + findId(images[2], true) + "\" " + "i4=\"" + findId(images[3], true) + "\" " + "i5=\"" + findId(images[4], true) + "\" " + "i6=\"" + findId(images[5], true) + "\" " + "i7=\"" + findId(images[6], true) + "\" " + "i8=\"" + findId(images[7], true) + "\" " + "i9=\"" + findId(images[8], true) + "\" />\n");
break;
}
continue;
}
case BORDER_TYPE_IMAGE_HORIZONTAL:
{
Image[] images = Accessor.getImages(border);
bw.write(" <border key=\"" + key + "\" type=\"imageH\" " + "i1=\"" + findId(images[0], true) + "\" " + "i2=\"" + findId(images[1], true) + "\" " + "i3=\"" + findId(images[2], true) + "\" />\n");
continue;
}
case BORDER_TYPE_IMAGE_VERTICAL:
{
Image[] images = Accessor.getImages(border);
bw.write(" <border key=\"" + key + "\" type=\"imageV\" " + "i1=\"" + findId(images[0], true) + "\" " + "i2=\"" + findId(images[1], true) + "\" " + "i3=\"" + findId(images[2], true) + "\" />\n");
continue;
}
}
continue;
}
// if this is a font
if (key.endsWith("font")) {
com.codename1.ui.Font f = (com.codename1.ui.Font) theme.get(key);
// is this a new font?
boolean newFont = f instanceof EditorFont;
if (newFont) {
bw.write(" <font key=\"" + key + "\" type=\"named\" " + "name=\"" + findId(f) + "\" />\n");
} else {
if (f instanceof EditorTTFFont && (((EditorTTFFont) f).getFontFile() != null || ((EditorTTFFont) f).getNativeFontName() != null)) {
EditorTTFFont ed = (EditorTTFFont) f;
String fname;
String ffName;
if (((EditorTTFFont) f).getNativeFontName() != null) {
fname = ((EditorTTFFont) f).getNativeFontName();
ffName = fname;
} else {
fname = ed.getFontFile().getName();
ffName = ((java.awt.Font) ed.getNativeFont()).getPSName();
}
bw.write(" <font key=\"" + key + "\" type=\"ttf\" " + "face=\"" + f.getFace() + "\" " + "style=\"" + f.getStyle() + "\" " + "size=\"" + f.getSize() + "\" " + "name=\"" + fname + "\" " + "family=\"" + ffName + "\" " + "sizeSettings=\"" + ed.getSizeSetting() + "\" " + "actualSize=\"" + ed.getActualSize() + "\" />\n");
} else {
bw.write(" <font key=\"" + key + "\" type=\"system\" " + "face=\"" + f.getFace() + "\" " + "style=\"" + f.getStyle() + "\" " + "size=\"" + f.getSize() + "\" />\n");
}
}
continue;
}
// if this is a background image
if (key.endsWith("bgImage")) {
bw.write(" <val key=\"" + key + "\" value=\"" + findId(theme.get(key), true) + "\" />\n");
continue;
}
if (key.endsWith("scaledImage")) {
bw.write(" <val key=\"" + key + "\" value=\"" + theme.get(key) + "\" />\n");
continue;
}
if (key.endsWith("derive")) {
bw.write(" <val key=\"" + key + "\" value=\"" + theme.get(key) + "\" />\n");
continue;
}
// if this is a background gradient
if (key.endsWith("bgGradient")) {
Object[] gradient = (Object[]) theme.get(key);
bw.write(" <gradient key=\"" + key + "\" color1=\"" + gradient[0] + "\"" + " color2=\"" + gradient[1] + "\"" + " posX=\"" + gradient[2] + "\"" + " posY=\"" + gradient[3] + "\"" + " radius=\"" + gradient[4] + "\" />\n");
continue;
}
if (key.endsWith(Style.BACKGROUND_TYPE) || key.endsWith(Style.BACKGROUND_ALIGNMENT)) {
bw.write(" <val key=\"" + key + "\" value=\"" + theme.get(key) + "\" />\n");
continue;
}
// thow an exception no idea what this is
throw new IOException("Error while trying to read theme property: " + key);
}
bw.write(" </theme>\n");
continue;
case MAGIC_FONT:
File legacyFont = new File(resourcesDir, normalizeFileName(resourceNames[iter]));
DataOutputStream legacyFontOut = new DataOutputStream(new FileOutputStream(legacyFont));
saveFont(legacyFontOut, false, resourceNames[iter]);
legacyFontOut.close();
bw.write(" <legacyFont name=\"" + xResourceName + "\" />\n");
continue;
case MAGIC_DATA:
{
File dataFile = new File(resourcesDir, normalizeFileName(resourceNames[iter]));
DataOutputStream dataFileOut = new DataOutputStream(new FileOutputStream(dataFile));
InputStream i = getData(resourceNames[iter]);
ByteArrayOutputStream outArray = new ByteArrayOutputStream();
int val = i.read();
while (val != -1) {
outArray.write(val);
val = i.read();
}
byte[] data = outArray.toByteArray();
dataFileOut.write(data);
dataFileOut.close();
bw.write(" <data name=\"" + xResourceName + "\" />\n");
continue;
}
case MAGIC_UI:
{
File uiXML = new File(resourcesDir, resourceNames[iter] + ".ui");
UIBuilderOverride u = new UIBuilderOverride();
com.codename1.ui.Container cnt = u.createContainer(this, resourceNames[iter]);
FileOutputStream fos = new FileOutputStream(uiXML);
writeUIXml(cnt, fos);
fos.close();
File ui = new File(resourcesDir, resourceNames[iter]);
DataOutputStream uiOut = new DataOutputStream(new FileOutputStream(ui));
InputStream i = getUi(resourceNames[iter]);
ByteArrayOutputStream outArray = new ByteArrayOutputStream();
int val = i.read();
while (val != -1) {
outArray.write(val);
val = i.read();
}
byte[] data = outArray.toByteArray();
uiOut.write(data);
uiOut.close();
bw.write(" <ui name=\"" + xResourceName + "\" />\n");
continue;
}
case MAGIC_L10N:
// we are getting the theme which allows us to acces the l10n data
bw.write(" <l10n name=\"" + xResourceName + "\">\n");
Hashtable<String, Object> l10n = getTheme(resourceNames[iter]);
for (String locale : l10n.keySet()) {
bw.write(" <lang name=\"" + locale + "\">\n");
Hashtable<String, String> current = (Hashtable<String, String>) l10n.get(locale);
for (String key : current.keySet()) {
String val = current.get(key);
bw.write(" <entry key=\"" + xmlize(key) + "\" value=\"" + xmlize(val) + "\" />\n");
}
bw.write(" </lang>\n");
}
bw.write(" </l10n>\n");
continue;
default:
throw new IOException("Corrupt theme file unrecognized magic number: " + Integer.toHexString(magic & 0xff));
}
}
bw.write("</resource>\n");
bw.close();
} finally {
overrideFile = overrideFileBackup;
overrideResource = overrideResourceBackup;
}
}
use of com.codename1.rad.ui.UI in project CodenameOne by codenameone.
the class CloudObject method unbindTree.
/**
* Clears the binding to this component tree
* @param ui the container whose children might be bound
*/
public void unbindTree(Container ui) {
int componentCount = ui.getComponentCount();
for (int iter = 0; iter < componentCount; iter++) {
Component c = ui.getComponentAt(iter);
if (c instanceof Container) {
unbindTree((Container) c);
continue;
}
String bind = c.getCloudBoundProperty();
if (bind != null && bind.length() > 0) {
String attributeName = c.getCloudDestinationProperty();
if (attributeName != null) {
unbindProperty(c, bind);
}
}
}
}
use of com.codename1.rad.ui.UI in project CodenameOne by codenameone.
the class FlowLayout method getPreferredSize.
/**
* {@inheritDoc}
*/
public Dimension getPreferredSize(Container parent) {
int parentWidth = parent.getWidth();
// display width can be larger on orientation change when the UI didn't have time to adapt
if (parentWidth == 0 || parentWidth > Display.getInstance().getDisplayWidth()) {
parent.invalidate();
}
int width = 0;
int height = 0;
int w = 0;
int numOfcomponents = parent.getComponentCount();
Style parentStyle = parent.getStyle();
int parentPadding = parentStyle.getHorizontalPadding();
for (int i = 0; i < numOfcomponents; i++) {
Component cmp = parent.getComponentAt(i);
height = Math.max(height, cmp.getPreferredH() + cmp.getStyle().getMarginTop() + cmp.getStyle().getMarginBottom());
int prefW = cmp.getPreferredW() + cmp.getStyle().getHorizontalMargins();
w += prefW;
// we need to break a line
if (parentWidth > parentPadding && w > parentWidth - parentPadding && i > 0) {
height += cmp.getPreferredH() + cmp.getStyle().getMarginTop() + cmp.getStyle().getMarginBottom();
width = Math.max(w, width);
w = prefW;
}
}
width = Math.max(w, width);
dim.setWidth(width + parent.getStyle().getPaddingLeftNoRTL() + parent.getStyle().getPaddingRightNoRTL());
dim.setHeight(height + parent.getStyle().getPaddingTop() + parent.getStyle().getPaddingBottom());
return dim;
}
Aggregations