diff --git a/Jenkinsfile b/Jenkinsfile
index d0ecd8e85a..7910c3890d 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -1,5 +1,45 @@
#!groovy
+class DockerParameters {
+
+ // 'docker build' would normally copy the whole build-dir to the container, changing the
+ // docker build directory avoids that overhead
+ def dir = 'docker'
+ def args = '--device /dev/kvm:/dev/kvm -v /var/local/container_shared/gradle_cache/$EXECUTOR_NUMBER:/home/user/.gradle -m=6.5G'
+ def label = 'LimitedEmulator'
+ def image = 'floriankanduth/paintroid_java17:latest'
+
+}
+
+def dockerParameters = new DockerParameters()
+
+def startEmulator(String android_version, String stageName) {
+ sh 'adb start-server'
+ // creates a new avd, and if it already exists it does nothing.
+ sh "echo no | avdmanager create avd --force --name android${android_version}" + " --package 'system-images;android-${android_version};default;x86_64'"
+ sh "/home/user/android/sdk/emulator/emulator -no-window -no-boot-anim -noaudio -avd android${android_version} > ${stageName}_emulator.log 2>&1 &"
+}
+
+def waitForEmulatorAndPressWakeUpKey() {
+ sh 'adb devices'
+ sh 'timeout 5m adb wait-for-device'
+ sh '''#!/bin/bash
+adb devices
+timeout 5m adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1;
+done'
+echo "Emulator started"
+'''
+ sh '''
+ adb shell settings put global window_animation_scale 0 &
+ adb shell settings put global transition_animation_scale 0 &
+ adb shell settings put global animator_duration_scale 0 &
+ '''
+
+
+ // In case the device went to sleep
+ sh 'adb shell input keyevent KEYCODE_WAKEUP'
+}
+
def reports = 'Paintroid/build/reports'
// place the cobertura xml relative to the source, so that the source can be found
@@ -22,7 +62,21 @@ def useDebugLabelParameter(defaultLabel) {
return env.DEBUG_LABEL?.trim() ? env.DEBUG_LABEL : defaultLabel
}
+def checkAnimationScale(scaleName) {
+ def output = sh(script: "adb shell settings get global ${scaleName}", returnStdout: true).trim()
+ if (output != "0" && output != "0.0") {
+ error("Animation scale '${scaleName}' is NOT disabled. Current value: ${output}")
+ } else {
+ echo("Animation scale '${scaleName}' is disabled (Value: ${output})")
+ }
+ }
+
pipeline {
+ environment {
+ ANDROID_VERSION = 33
+ ADB_INSTALL_TIMEOUT = 60
+ }
+
parameters {
string name: 'DEBUG_LABEL', defaultValue: '', description: 'For debugging when entered will be used as label to decide on which slaves the jobs will run.'
booleanParam name: 'BUILD_WITH_CATROID', defaultValue: false, description: 'When checked then the current Paintroid build will be built with the current develop branch of Catroid'
@@ -30,10 +84,10 @@ pipeline {
}
agent {
- docker {
- image 'catrobat/catrobat-paintroid:stable'
- args '--device /dev/kvm:/dev/kvm -v /var/local/container_shared/gradle_cache/$EXECUTOR_NUMBER:/home/user/.gradle -m=6.5G'
- label 'LimitedEmulator'
+ docker {
+ image dockerParameters.image
+ args dockerParameters.args
+ label dockerParameters.label
alwaysPull true
}
}
@@ -70,14 +124,14 @@ pipeline {
sh 'rm -rf Catroid; mkdir Catroid'
dir('Catroid') {
git branch: params.CATROID_BRANCH, url: 'https://github.com/Catrobat/Catroid.git'
- sh "rm -f catroid/src/main/libs/*.aar"
- sh "mv -f ../colorpicker/build/outputs/aar/colorpicker-debug.aar catroid/src/main/libs/colorpicker-LOCAL.aar"
- sh "mv -f ../Paintroid/build/outputs/aar/Paintroid-debug.aar catroid/src/main/libs/Paintroid-LOCAL.aar"
+ sh 'rm -f catroid/src/main/libs/*.aar'
+ sh 'mv -f ../colorpicker/build/outputs/aar/colorpicker-debug.aar catroid/src/main/libs/colorpicker-LOCAL.aar'
+ sh 'mv -f ../Paintroid/build/outputs/aar/Paintroid-debug.aar catroid/src/main/libs/Paintroid-LOCAL.aar'
}
renameApks("${env.BRANCH_NAME}-${env.BUILD_NUMBER}")
dir('Catroid') {
- archiveArtifacts "catroid/src/main/libs/*.aar"
- sh "./gradlew assembleCatroidDebug"
+ archiveArtifacts 'catroid/src/main/libs/*.aar'
+ sh './gradlew assembleCatroidDebug'
archiveArtifacts 'catroid/build/outputs/apk/catroid/debug/catroid-catroid-debug.apk'
}
}
@@ -114,9 +168,16 @@ pipeline {
stage('Device Tests') {
steps {
- sh "echo no | avdmanager create avd --force --name android28 --package 'system-images;android-28;default;x86_64'"
- sh "/home/user/android/sdk/emulator/emulator -no-window -no-boot-anim -noaudio -avd android28 > /dev/null 2>&1 &"
- sh './gradlew -PenableCoverage -Pjenkins -Pemulator=android28 -Pci createDebugCoverageReport -i'
+ catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
+ startEmulator(ANDROID_VERSION, 'device_tests')
+ waitForEmulatorAndPressWakeUpKey()
+ script {
+ checkAnimationScale("window_animation_scale")
+ checkAnimationScale("transition_animation_scale")
+ checkAnimationScale("animator_duration_scale")
+ }
+ sh "./gradlew disableAnimations -PenableCoverage -Pjenkins -Pemulator=android${android_version} -Pci createDebugCoverageReport -i"
+ }
}
post {
always {
@@ -145,4 +206,4 @@ pipeline {
notifyChat()
}
}
-}
+}
\ No newline at end of file
diff --git a/Paintroid/build.gradle b/Paintroid/build.gradle
index 9ffbde1915..c0c90f81c2 100644
--- a/Paintroid/build.gradle
+++ b/Paintroid/build.gradle
@@ -17,35 +17,33 @@
* along with this program. If not, see .
*/
-apply plugin: 'com.android.library'
-apply plugin: 'com.hiya.jacoco-android'
-apply plugin: 'com.getkeepsafe.dexcount'
-apply plugin: 'kotlin-android'
-apply plugin: 'org.catrobat.gradle.androidemulators'
-apply plugin: 'maven-publish'
+plugins {
+ id "com.android.library"
+ id "jacoco"
+ id "com.getkeepsafe.dexcount"
+ id "org.jetbrains.kotlin.android"
+ id "org.catrobat.gradle.androidemulators"
+ id "maven-publish"
+}
-apply from: 'gradle/adb_tasks.gradle'
-apply from: 'gradle/code_quality_tasks.gradle'
+apply from: "gradle/adb_tasks.gradle"
+apply from: "gradle/code_quality_tasks.gradle"
emulators {
- install project.hasProperty('installSdk')
-
- dependencies {
- sdk()
- }
+ install project.hasProperty("installSdk")
+ dependencies { sdk() }
- emulator 'android28', {
+ emulator "android28", {
avd {
- systemImage = 'system-images;android-28;default;x86_64'
+ systemImage = "system-images;android-28;default;x86_64"
sdcardSizeMb = 1024
- hardwareProperties += ['hw.ramSize': 4096, 'vm.heapSize': 1024]
- screenDensity = 'xhdpi'
+ hardwareProperties += ["hw.ramSize": 4096, "vm.heapSize": 1024]
+ screenDensity = "xhdpi"
}
-
parameters {
- resolution = '768x1280'
- language = 'en'
- country = 'US'
+ resolution = "768x1280"
+ language = "en"
+ country = "US"
}
}
}
@@ -54,54 +52,50 @@ jacoco {
toolVersion = "0.8.7"
}
-jacocoAndroidUnitTestReport {
- csv.enabled false
- html.enabled true
- xml.enabled true
- destination project.getBuildDir().getPath() + "/reports/jacoco/jacocoTestDebugUnitTestReport"
-}
-
android {
- compileSdkVersion rootProject.ext.androidCompileSdkVersion
+ namespace "org.catrobat.paintroid"
+
+ // New AGP DSL
+ compileSdk = rootProject.ext.androidCompileSdkVersion
defaultConfig {
- minSdkVersion rootProject.ext.androidMinSdkVersion
- targetSdkVersion rootProject.ext.androidTargetSdkVersion
- testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
- versionCode rootProject.ext.androidVersionCode
- versionName rootProject.ext.androidVersionName
+ minSdk = rootProject.ext.androidMinSdkVersion
+ targetSdk = rootProject.ext.androidTargetSdkVersion
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildFeatures {
+ buildConfig = true
}
compileOptions {
- sourceCompatibility JavaVersion.VERSION_11
- targetCompatibility JavaVersion.VERSION_11
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
}
+ kotlinOptions { jvmTarget = "17" }
buildTypes {
release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- signedRelease {
+ minifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android.txt"),
+ "proguard-rules.pro"
+ )
}
+ create("signedRelease")
debug {
- testCoverageEnabled = project.hasProperty('enableCoverage')
- // Multidex is required as espresso and mockito/bytebuddy are adding more functions
- // than should be allowed by law.
- // See https://github.com/mockito/mockito/issues/1112
- multiDexEnabled true
}
}
- lintOptions {
- // specific ignores should be defined via lint.xml file
- lintConfig file('config/lint.xml')
- ignore 'ClickableViewAccessibility', 'StaticFieldLeak', 'GradleDependency', 'OldTargetApi', 'LintBaseline'
- textReport true
- xmlReport true
- htmlReport true
- xmlOutput file("build/reports/lint-report.xml")
- htmlOutput file("build/reports/lint-report.html")
+ lint {
+ lintConfig file("config/lint.xml")
+ disable "ClickableViewAccessibility", "StaticFieldLeak",
+ "GradleDependency", "OldTargetApi", "LintBaseline"
+ textReport = true
+ xmlReport = true
+ htmlReport = true
+ xmlOutput = file("build/reports/lint-report.xml")
+ htmlOutput = file("build/reports/lint-report.html")
}
testOptions {
@@ -111,54 +105,51 @@ android {
packagingOptions {
resources {
- excludes += ['META-INF/AL2.0', 'META-INF/LGPL2.1', "**/attach_hotspot_windows.dll"]
- merges += ['META-INF/licenses/ASM']
+ excludes += ["META-INF/AL2.0", "META-INF/LGPL2.1", "**/attach_hotspot_windows.dll"]
+ merges += ["META-INF/licenses/ASM"]
}
}
}
dependencies {
- implementation 'androidx.appcompat:appcompat:1.0.0'
- implementation 'com.google.android.material:material:1.2.1'
- implementation project(':colorpicker')
+ implementation "androidx.appcompat:appcompat:1.0.0"
+ implementation "com.google.android.material:material:1.2.1"
+ implementation project(":colorpicker")
- implementation 'androidx.core:core-ktx:1.3.2'
+ implementation "androidx.core:core-ktx:1.3.2"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
- implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8'
- implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
- implementation 'androidx.exifinterface:exifinterface:1.3.2'
- implementation 'com.esotericsoftware:kryo:5.5.0'
- implementation 'id.zelory:compressor:2.1.1'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
-
- debugImplementation 'androidx.multidex:multidex:2.0.0'
-
- implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
- implementation 'com.jraska:falcon:2.2.0'
-
- testImplementation 'junit:junit:4.12'
- testImplementation 'org.mockito:mockito-core:2.18.3'
- testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0'
-
- androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.3'
- androidTestImplementation 'androidx.test.ext:junit:1.1.3'
- androidTestImplementation 'androidx.test:rules:1.1.1'
- androidTestImplementation 'org.mockito:mockito-android:3.6.28'
- androidTestImplementation 'tools.fastlane:screengrab:2.1.0'
- androidTestImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0'
-
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
- androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.1.0'
- androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.0'
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8"
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8"
+ implementation "androidx.exifinterface:exifinterface:1.3.2"
+ implementation "com.esotericsoftware:kryo:5.5.0"
+ implementation "id.zelory:compressor:2.1.1"
+ implementation "androidx.constraintlayout:constraintlayout:2.1.4"
+ implementation 'androidx.test:monitor:1.8.0'
+
+ debugImplementation "androidx.multidex:multidex:2.0.0"
+
+ implementation "com.nostra13.universalimageloader:universal-image-loader:1.9.5"
+ implementation "com.jraska:falcon:2.2.0"
+
+ testImplementation "junit:junit:4.12"
+ testImplementation "org.mockito:mockito-core:2.18.3"
+ testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
+
+ androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.3"
+ androidTestImplementation "androidx.test.ext:junit:1.1.3"
+ androidTestImplementation "androidx.test:rules:1.1.1"
+ androidTestImplementation "org.mockito:mockito-android:3.6.28"
+ androidTestImplementation "tools.fastlane:screengrab:2.1.0"
+ androidTestImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
+
+ androidTestImplementation "androidx.test.espresso:espresso-core:3.5.1"
+ androidTestImplementation "androidx.test.espresso:espresso-contrib:3.1.0"
+ androidTestImplementation "androidx.test.espresso:espresso-intents:3.1.0"
androidTestImplementation "androidx.test.uiautomator:uiautomator:2.2.0"
testImplementation "androidx.test:core-ktx:1.4.0"
- implementation 'com.android.support.test.espresso:espresso-idling-resource:3.1.0'
-}
-tasks.withType(Javadoc).all {
- enabled = false
+ implementation "androidx.test.espresso:espresso-idling-resource:3.5.1"
}
-if (project.hasProperty('jenkins')) {
- android.dexOptions.preDexLibraries = false
-}
+tasks.withType(Javadoc).configureEach { enabled = false }
+
diff --git a/Paintroid/gradle/code_quality_tasks.gradle b/Paintroid/gradle/code_quality_tasks.gradle
index c86a9788de..00d17898e0 100644
--- a/Paintroid/gradle/code_quality_tasks.gradle
+++ b/Paintroid/gradle/code_quality_tasks.gradle
@@ -42,30 +42,30 @@ task checkstyle(type: Checkstyle) {
classpath = files()
- // needed for console output of warnings/errors
- showViolations true
- ignoreFailures false
+ // console printing is automatic; use ignoreFailures to fail or not
+ ignoreFailures = false
reports {
- xml.enabled = true
- xml.destination file("build/reports/checkstyle.xml")
+ xml.required.set(true)
+ html.required.set(false)
+ xml.outputLocation.set(file("$buildDir/reports/checkstyle.xml"))
}
}
task pmd(type: Pmd) {
ruleSetFiles = files('config/pmd.xml')
- ruleSets = []
+ ruleSets = [] // don't use built-in default sets
source '.'
include '**/*.java'
exclude '**/gen/**', '**/build/**', '**/res/**'
- ignoreFailures false
+ ignoreFailures = false
reports {
- xml.enabled = true
- html.enabled = true
- xml.destination file("build/reports/pmd.xml")
+ xml.required.set(true)
+ html.required.set(true)
+ xml.outputLocation.set(file("$buildDir/reports/pmd.xml"))
}
}
diff --git a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/CatrobatImageIOIntegrationTest.kt b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/CatrobatImageIOIntegrationTest.kt
index 86ee6283b3..2fe9b47de3 100644
--- a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/CatrobatImageIOIntegrationTest.kt
+++ b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/CatrobatImageIOIntegrationTest.kt
@@ -20,7 +20,9 @@
package org.catrobat.paintroid.test.espresso
+import android.Manifest
import android.net.Uri
+import android.os.Build
import android.os.Environment
import androidx.test.espresso.Espresso
import androidx.test.espresso.Espresso.onView
@@ -32,15 +34,14 @@ import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.ActivityTestRule
-import androidx.test.rule.GrantPermissionRule
import org.catrobat.paintroid.FileIO
import org.catrobat.paintroid.MainActivity
import org.catrobat.paintroid.command.serialization.CommandSerializer
import org.catrobat.paintroid.R
import org.catrobat.paintroid.common.CATROBAT_IMAGE_ENDING
import org.catrobat.paintroid.test.espresso.util.DrawingSurfaceLocationProvider
-import org.catrobat.paintroid.test.espresso.util.EspressoUtils
import org.catrobat.paintroid.test.espresso.util.UiInteractions
import org.catrobat.paintroid.test.espresso.util.wrappers.DrawingSurfaceInteraction.Companion.onDrawingSurfaceView
import org.catrobat.paintroid.test.espresso.util.wrappers.TopBarViewInteraction
@@ -52,6 +53,7 @@ import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
+import org.junit.rules.RuleChain
import org.junit.runner.RunWith
import java.io.File
@@ -59,14 +61,12 @@ import java.io.File
class CatrobatImageIOIntegrationTest {
@get:Rule
- val launchActivityRule = ActivityTestRule(MainActivity::class.java)
+ val launchActivityRule =
+ ActivityTestRule(MainActivity::class.java, true, false)
@get:Rule
val screenshotOnFailRule = ScreenshotOnFailRule()
- @get:Rule
- val grantPermissionRule: GrantPermissionRule = EspressoUtils.grantPermissionRulesVersionCheck()
-
private var uriFile: Uri? = null
private lateinit var activity: MainActivity
@@ -75,12 +75,38 @@ class CatrobatImageIOIntegrationTest {
}
@Before
- fun setUp() { activity = launchActivityRule.activity }
+ fun setUp() {
+ val inst = InstrumentationRegistry.getInstrumentation()
+ val targetPkg = inst.targetContext.packageName
+ val perms = when {
+ Build.VERSION.SDK_INT >= 34 -> arrayOf(
+ Manifest.permission.READ_MEDIA_IMAGES,
+ Manifest.permission.READ_MEDIA_VIDEO,
+ "android.permission.READ_MEDIA_VISUAL_USER_SELECTED"
+ )
+ Build.VERSION.SDK_INT >= 33 -> arrayOf(
+ Manifest.permission.READ_MEDIA_IMAGES,
+ Manifest.permission.READ_MEDIA_VIDEO
+ )
+ else -> arrayOf(
+ Manifest.permission.READ_EXTERNAL_STORAGE
+ )
+ }
+ perms.forEach {
+ try {
+ inst.uiAutomation.grantRuntimePermission(targetPkg, it)
+ } catch (_: Exception) {
+ }
+ }
+
+ launchActivityRule.launchActivity(null)
+ activity = launchActivityRule.activity
+ }
@After
fun tearDown() {
val imagesDirectory =
- Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString()
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString()
val pathToFile = imagesDirectory + File.separator + IMAGE_NAME + "." + CATROBAT_IMAGE_ENDING
val imageFile = File(pathToFile)
if (imageFile.exists()) {
diff --git a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/LayerBackgroundTest.kt b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/LayerBackgroundTest.kt
index bfbf53ff64..d9bf34e538 100644
--- a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/LayerBackgroundTest.kt
+++ b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/LayerBackgroundTest.kt
@@ -49,7 +49,7 @@ class LayerBackgroundTest(private val language: String) {
@Test
fun testOneLayer() {
var actualBackground = getActualBackground(0)
- Assert.assertEquals(actualBackground, getSingleBackground()?.constantState)
+ Assert.assertEquals(actualBackground, getSingleBackground().constantState)
}
@Test
@@ -61,8 +61,8 @@ class LayerBackgroundTest(private val language: String) {
var backgroundTop = getActualBackground(0)
var backgroundBottom = getActualBackground(1)
- Assert.assertEquals(backgroundTop, getTopBackground(true)?.constantState)
- Assert.assertEquals(backgroundBottom, getBottomBackground(false)?.constantState)
+ Assert.assertEquals(backgroundTop, getTopBackground(true).constantState)
+ Assert.assertEquals(backgroundBottom, getBottomBackground(false).constantState)
}
@Test
@@ -75,8 +75,8 @@ class LayerBackgroundTest(private val language: String) {
var backgroundTop = getActualBackground(0)
var backgroundBottom = getActualBackground(1)
- Assert.assertEquals(backgroundTop, getTopBackground(false)?.constantState)
- Assert.assertEquals(backgroundBottom, getBottomBackground(true)?.constantState)
+ Assert.assertEquals(backgroundTop, getTopBackground(false).constantState)
+ Assert.assertEquals(backgroundBottom, getBottomBackground(true).constantState)
}
@Test
@@ -90,9 +90,9 @@ class LayerBackgroundTest(private val language: String) {
var backgroundCenter = getActualBackground(1)
var backgroundBottom = getActualBackground(2)
- Assert.assertEquals(backgroundTop, getTopBackground(true)?.constantState)
+ Assert.assertEquals(backgroundTop, getTopBackground(true).constantState)
Assert.assertEquals(backgroundCenter, getCenterBackground(false)?.constantState)
- Assert.assertEquals(backgroundBottom, getBottomBackground(false)?.constantState)
+ Assert.assertEquals(backgroundBottom, getBottomBackground(false).constantState)
}
@Test
@@ -107,9 +107,9 @@ class LayerBackgroundTest(private val language: String) {
var backgroundCenter = getActualBackground(1)
var backgroundBottom = getActualBackground(2)
- Assert.assertEquals(backgroundTop, getTopBackground(false)?.constantState)
+ Assert.assertEquals(backgroundTop, getTopBackground(false).constantState)
Assert.assertEquals(backgroundCenter, getCenterBackground(true)?.constantState)
- Assert.assertEquals(backgroundBottom, getBottomBackground(false)?.constantState)
+ Assert.assertEquals(backgroundBottom, getBottomBackground(false).constantState)
}
@Test
@@ -125,9 +125,9 @@ class LayerBackgroundTest(private val language: String) {
var backgroundCenter = getActualBackground(1)
var backgroundBottom = getActualBackground(2)
- Assert.assertEquals(backgroundTop, getTopBackground(false)?.constantState)
+ Assert.assertEquals(backgroundTop, getTopBackground(false).constantState)
Assert.assertEquals(backgroundCenter, getCenterBackground(false)?.constantState)
- Assert.assertEquals(backgroundBottom, getBottomBackground(true)?.constantState)
+ Assert.assertEquals(backgroundBottom, getBottomBackground(true).constantState)
}
@Test
@@ -143,10 +143,10 @@ class LayerBackgroundTest(private val language: String) {
val backgroundLowerCenter = getActualBackground(2)
val backgroundBottom = getActualBackground(3)
- Assert.assertEquals(backgroundTop, getTopBackground(true)?.constantState)
+ Assert.assertEquals(backgroundTop, getTopBackground(true).constantState)
Assert.assertEquals(backgroundUpperCenter, getCenterBackground(false)?.constantState)
Assert.assertEquals(backgroundLowerCenter, getCenterBackground(false)?.constantState)
- Assert.assertEquals(backgroundBottom, getBottomBackground(false)?.constantState)
+ Assert.assertEquals(backgroundBottom, getBottomBackground(false).constantState)
}
@Test
@@ -163,10 +163,10 @@ class LayerBackgroundTest(private val language: String) {
val backgroundLowerCenter = getActualBackground(2)
val backgroundBottom = getActualBackground(3)
- Assert.assertEquals(backgroundTop, getTopBackground(false)?.constantState)
+ Assert.assertEquals(backgroundTop, getTopBackground(false).constantState)
Assert.assertEquals(backgroundUpperCenter, getCenterBackground(true)?.constantState)
Assert.assertEquals(backgroundLowerCenter, getCenterBackground(false)?.constantState)
- Assert.assertEquals(backgroundBottom, getBottomBackground(false)?.constantState)
+ Assert.assertEquals(backgroundBottom, getBottomBackground(false).constantState)
}
@Test
@@ -184,10 +184,10 @@ class LayerBackgroundTest(private val language: String) {
val backgroundLowerCenter = getActualBackground(2)
val backgroundBottom = getActualBackground(3)
- Assert.assertEquals(backgroundTop, getTopBackground(false)?.constantState)
+ Assert.assertEquals(backgroundTop, getTopBackground(false).constantState)
Assert.assertEquals(backgroundUpperCenter, getCenterBackground(false)?.constantState)
Assert.assertEquals(backgroundLowerCenter, getCenterBackground(true)?.constantState)
- Assert.assertEquals(backgroundBottom, getBottomBackground(false)?.constantState)
+ Assert.assertEquals(backgroundBottom, getBottomBackground(false).constantState)
}
@Test
@@ -205,14 +205,14 @@ class LayerBackgroundTest(private val language: String) {
val backgroundLowerCenter = getActualBackground(2)
val backgroundBottom = getActualBackground(3)
- Assert.assertEquals(backgroundTop, getTopBackground(false)?.constantState)
+ Assert.assertEquals(backgroundTop, getTopBackground(false).constantState)
Assert.assertEquals(backgroundUpperCenter, getCenterBackground(false)?.constantState)
Assert.assertEquals(backgroundLowerCenter, getCenterBackground(false)?.constantState)
- Assert.assertEquals(backgroundBottom, getBottomBackground(true)?.constantState)
+ Assert.assertEquals(backgroundBottom, getBottomBackground(true).constantState)
}
private fun getActualBackground(position: Int): Drawable.ConstantState? {
- val layout = layerAdapter?.getViewHolderAt(position)?.getViewLayout()
+ val layout = layerAdapter.getViewHolderAt(position)?.getViewLayout()
return layout?.background?.constantState
}
diff --git a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/OraFileIntentTest.kt b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/OraFileIntentTest.kt
index bad8c3b90c..1a6cb40583 100644
--- a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/OraFileIntentTest.kt
+++ b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/OraFileIntentTest.kt
@@ -124,7 +124,7 @@ class OraFileIntentTest {
} catch (e: IOException) {
throw AssertionError("Picture file could not be created.", e)
}
- val imageFile = File(imageUri!!.path, "testfile.ora")
+ val imageFile = File(imageUri.path, "testfile.ora")
deletionFileList!!.add(imageFile)
return imageUri
}
diff --git a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/SaveCompressImageIntegrationTest.kt b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/SaveCompressImageIntegrationTest.kt
index 8695392047..ed66b8fe93 100644
--- a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/SaveCompressImageIntegrationTest.kt
+++ b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/SaveCompressImageIntegrationTest.kt
@@ -119,11 +119,12 @@ class SaveCompressImageIntegrationTest {
val options = BitmapFactory.Options()
options.inMutable = true
- val compressedBitmap = Objects.requireNonNull(
- activity?.model?.savedPictureUri
- )?.let {
- activity?.let { it1 ->
- getScaledBitmapFromUri(it1.contentResolver, it, activity?.applicationContext)
+ val savedUri = activity?.model?.savedPictureUri
+ Assert.assertNotNull("Saved picture URI should not be null", savedUri) // Fail test if null
+
+ val compressedBitmap = savedUri?.let { uri -> // 'uri' is now non-nullable Uri
+ activity?.let { activityNonNull ->
+ getScaledBitmapFromUri(activityNonNull.contentResolver, uri, activityNonNull.applicationContext)
}
}
val testBitmap = getBitmapFromFile(testImageFile)
diff --git a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/ClipboardCommandTest.kt b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/ClipboardCommandTest.kt
index c4908c687a..e95f7e99b6 100644
--- a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/ClipboardCommandTest.kt
+++ b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/ClipboardCommandTest.kt
@@ -52,7 +52,7 @@ class ClipboardCommandTest {
val bitmapUnderTest = canvasBitmapUnderTest.copy(Bitmap.Config.ARGB_8888, true)
val layerUnderTest = Layer(bitmapUnderTest)
canvasUnderTest = Canvas()
- canvasUnderTest!!.setBitmap(canvasBitmapUnderTest)
+ canvasUnderTest.setBitmap(canvasBitmapUnderTest)
pointUnderTest = PointF((INITIAL_WIDTH / 2).toFloat(), (INITIAL_HEIGHT / 2).toFloat())
layerModel!!.addLayerAt(0, layerUnderTest)
layerModel!!.currentLayer = layerUnderTest
@@ -70,7 +70,7 @@ class ClipboardCommandTest {
val model = LayerModel()
model.addLayerAt(0, layer)
model.currentLayer = layer
- commandUnderTest!!.run(canvasUnderTest!!, model)
+ commandUnderTest!!.run(canvasUnderTest, model)
PaintroidAsserts.assertBitmapEquals(stampBitmapUnderTest, canvasBitmapUnderTest)
Assert.assertNull("Stamp bitmap not recycled.", commandUnderTest!!.bitmap)
Assert.assertNotNull("Bitmap not stored", commandUnderTest!!.fileToStoredBitmap)
@@ -78,17 +78,18 @@ class ClipboardCommandTest {
val secondModel = LayerModel()
secondModel.addLayerAt(0, secondLayer)
secondModel.currentLayer = secondLayer
- commandUnderTest!!.run(canvasUnderTest!!, secondModel)
+ commandUnderTest!!.run(canvasUnderTest, secondModel)
PaintroidAsserts.assertBitmapEquals(stampBitmapUnderTest, canvasBitmapUnderTest)
}
@Test
fun testRunRotateStamp() {
- stampBitmapUnderTest!!.setPixel(0, 0, Color.GREEN)
- commandUnderTest = ClipboardCommand(stampBitmapUnderTest!!, Point(pointUnderTest!!.x.toInt(), pointUnderTest!!.y.toInt()), canvasBitmapUnderTest!!.width.toFloat(), canvasBitmapUnderTest!!.height.toFloat(), 180f)
- commandUnderTest!!.run(canvasUnderTest!!, LayerModel())
- stampBitmapUnderTest!!.setPixel(0, 0, Color.CYAN)
- stampBitmapUnderTest!!.setPixel(stampBitmapUnderTest!!.width - 1, stampBitmapUnderTest!!.height - 1,
+ stampBitmapUnderTest.setPixel(0, 0, Color.GREEN)
+ commandUnderTest = ClipboardCommand(stampBitmapUnderTest, Point(pointUnderTest!!.x.toInt(), pointUnderTest!!.y.toInt()), canvasBitmapUnderTest!!.width.toFloat(), canvasBitmapUnderTest!!.height.toFloat(), 180f)
+ commandUnderTest!!.run(canvasUnderTest, LayerModel())
+ stampBitmapUnderTest.setPixel(0, 0, Color.CYAN)
+ stampBitmapUnderTest.setPixel(
+ stampBitmapUnderTest.width - 1, stampBitmapUnderTest.height - 1,
Color.GREEN)
PaintroidAsserts.assertBitmapEquals(stampBitmapUnderTest, canvasBitmapUnderTest)
Assert.assertNull("Stamp bitmap not recycled.", commandUnderTest!!.bitmap)
@@ -120,7 +121,7 @@ class ClipboardCommandTest {
fun testStoreBitmap() {
var storedBitmap: File? = null
try {
- val bitmapCopy = canvasBitmapUnderTest!!.copy(canvasBitmapUnderTest!!.config, canvasBitmapUnderTest!!.isMutable)
+ val bitmapCopy = canvasBitmapUnderTest.copy(canvasBitmapUnderTest.config ?: Bitmap.Config.ARGB_8888, canvasBitmapUnderTest.isMutable)
commandUnderTest!!.storeBitmap(bitmapCopy, bitmapCopy.width.toFloat(), bitmapCopy.height.toFloat())
storedBitmap = commandUnderTest!!.fileToStoredBitmap
Assert.assertNotNull(storedBitmap)
diff --git a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/CropCommandTest.kt b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/CropCommandTest.kt
index 7bbd3b5009..632936c77f 100644
--- a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/CropCommandTest.kt
+++ b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/CropCommandTest.kt
@@ -43,16 +43,16 @@ class CropCommandTest {
@Before
fun setUp() {
layerModel = LayerModel()
- layerModel!!.width = INITIAL_WIDTH
- layerModel!!.height = INITIAL_HEIGHT
+ layerModel.width = INITIAL_WIDTH
+ layerModel.height = INITIAL_HEIGHT
val canvasBitmapUnderTest = Bitmap.createBitmap(INITIAL_WIDTH, INITIAL_HEIGHT, Bitmap.Config.ARGB_8888)
canvasBitmapUnderTest.eraseColor(BITMAP_BASE_COLOR)
bitmapUnderTest = canvasBitmapUnderTest.copy(Bitmap.Config.ARGB_8888, true)
layerUnderTest = Layer(bitmapUnderTest)
canvasUnderTest = Canvas()
- canvasUnderTest!!.setBitmap(canvasBitmapUnderTest)
- layerModel!!.addLayerAt(0, layerUnderTest!!)
- layerModel!!.currentLayer = layerUnderTest
+ canvasUnderTest.setBitmap(canvasBitmapUnderTest)
+ layerModel.addLayerAt(0, layerUnderTest)
+ layerModel.currentLayer = layerUnderTest
resizeCoordinateXLeft = 0
resizeCoordinateYTop = 0
resizeCoordinateXRight = bitmapUnderTest.width - 1
@@ -64,16 +64,16 @@ class CropCommandTest {
@Test
fun testIfBitmapIsCropped() {
- val widthOriginal = bitmapUnderTest!!.width
- val heightOriginal = bitmapUnderTest!!.height
+ val widthOriginal = bitmapUnderTest.width
+ val heightOriginal = bitmapUnderTest.height
resizeCoordinateXLeft = 1
resizeCoordinateYTop = 1
- resizeCoordinateXRight = bitmapUnderTest!!.width - 2
- resizeCoordinateYBottom = bitmapUnderTest!!.height - 2
+ resizeCoordinateXRight = bitmapUnderTest.width - 2
+ resizeCoordinateYBottom = bitmapUnderTest.height - 2
commandUnderTest = CropCommand(resizeCoordinateXLeft, resizeCoordinateYTop,
resizeCoordinateXRight, resizeCoordinateYBottom, maximumBitmapResolution)
- commandUnderTest.run(canvasUnderTest!!, layerModel!!)
- val croppedBitmap = layerUnderTest!!.bitmap
+ commandUnderTest.run(canvasUnderTest, layerModel)
+ val croppedBitmap = layerUnderTest.bitmap
Assert.assertEquals("Cropping failed, width not correct ", (widthOriginal - resizeCoordinateXLeft - (widthOriginal - (resizeCoordinateXRight + 1))).toLong(), croppedBitmap.width.toLong())
Assert.assertEquals("Cropping failed, height not correct ", (heightOriginal - resizeCoordinateYTop - (widthOriginal - (resizeCoordinateYBottom + 1))).toLong(), croppedBitmap.height.toLong())
croppedBitmap.recycle()
@@ -81,16 +81,16 @@ class CropCommandTest {
@Test
fun testIfBitmapIsEnlarged() {
- val widthOriginal = bitmapUnderTest!!.width
- val heightOriginal = bitmapUnderTest!!.height
+ val widthOriginal = bitmapUnderTest.width
+ val heightOriginal = bitmapUnderTest.height
resizeCoordinateXLeft = -1
resizeCoordinateYTop = -1
- resizeCoordinateXRight = bitmapUnderTest!!.width
- resizeCoordinateYBottom = bitmapUnderTest!!.height
+ resizeCoordinateXRight = bitmapUnderTest.width
+ resizeCoordinateYBottom = bitmapUnderTest.height
commandUnderTest = CropCommand(resizeCoordinateXLeft, resizeCoordinateYTop,
resizeCoordinateXRight, resizeCoordinateYBottom, maximumBitmapResolution)
- commandUnderTest.run(canvasUnderTest!!, layerModel!!)
- val enlargedBitmap = layerUnderTest!!.bitmap
+ commandUnderTest.run(canvasUnderTest, layerModel)
+ val enlargedBitmap = layerUnderTest.bitmap
Assert.assertEquals("Enlarging failed, width not correct ", (widthOriginal - resizeCoordinateXLeft - (widthOriginal - (resizeCoordinateXRight + 1))).toLong(), enlargedBitmap.width.toLong())
Assert.assertEquals("Enlarging failed, height not correct ", (heightOriginal - resizeCoordinateYTop - (widthOriginal - (resizeCoordinateYBottom + 1))).toLong(), enlargedBitmap.height.toLong())
enlargedBitmap.recycle()
@@ -98,16 +98,16 @@ class CropCommandTest {
@Test
fun testIfBitmapIsShifted() {
- val widthOriginal = bitmapUnderTest!!.width
- val heightOriginal = bitmapUnderTest!!.height
- resizeCoordinateXLeft = bitmapUnderTest!!.width / 2 - 1
- resizeCoordinateYTop = bitmapUnderTest!!.height / 2 - 1
- resizeCoordinateXRight = resizeCoordinateXLeft + bitmapUnderTest!!.width - 1
- resizeCoordinateYBottom = resizeCoordinateYTop + bitmapUnderTest!!.height - 1
+ val widthOriginal = bitmapUnderTest.width
+ val heightOriginal = bitmapUnderTest.height
+ resizeCoordinateXLeft = bitmapUnderTest.width / 2 - 1
+ resizeCoordinateYTop = bitmapUnderTest.height / 2 - 1
+ resizeCoordinateXRight = resizeCoordinateXLeft + bitmapUnderTest.width - 1
+ resizeCoordinateYBottom = resizeCoordinateYTop + bitmapUnderTest.height - 1
commandUnderTest = CropCommand(resizeCoordinateXLeft, resizeCoordinateYTop,
resizeCoordinateXRight, resizeCoordinateYBottom, maximumBitmapResolution)
- commandUnderTest.run(canvasUnderTest!!, layerModel!!)
- val enlargedBitmap = layerUnderTest!!.bitmap
+ commandUnderTest.run(canvasUnderTest, layerModel)
+ val enlargedBitmap = layerUnderTest.bitmap
Assert.assertEquals("Enlarging failed, width not correct ", widthOriginal.toLong(), enlargedBitmap.width.toLong())
Assert.assertEquals("Enlarging failed, height not correct ", heightOriginal.toLong(), enlargedBitmap.height.toLong())
enlargedBitmap.recycle()
@@ -115,41 +115,49 @@ class CropCommandTest {
@Test
fun testIfMaximumResolutionIsRespected() {
- val widthOriginal = bitmapUnderTest!!.width
- val heightOriginal = bitmapUnderTest!!.height
+ val widthOriginal = bitmapUnderTest.width
+ val heightOriginal = bitmapUnderTest.height
commandUnderTest = CropCommand(0, 0, widthOriginal * 2, heightOriginal * 2, maximumBitmapResolution)
- commandUnderTest.run(canvasUnderTest!!, layerModel!!)
- Assert.assertEquals("Width should not have changed", widthOriginal.toLong(), layerUnderTest!!.bitmap.width.toLong())
- Assert.assertEquals("Height should not have changed", heightOriginal.toLong(), layerUnderTest!!.bitmap.height.toLong())
+ commandUnderTest.run(canvasUnderTest, layerModel)
+ Assert.assertEquals("Width should not have changed", widthOriginal.toLong(), layerUnderTest.bitmap.width.toLong())
+ Assert.assertEquals("Height should not have changed", heightOriginal.toLong(), layerUnderTest.bitmap.height.toLong())
}
@Test
fun testIfBitmapIsNotResizedWithInvalidBounds() {
- val originalBitmap = layerUnderTest!!.bitmap
- commandUnderTest = CropCommand(bitmapUnderTest!!.width, 0, bitmapUnderTest!!.width,
+ val originalBitmap = layerUnderTest.bitmap
+ commandUnderTest = CropCommand(
+ bitmapUnderTest.width, 0, bitmapUnderTest.width,
0, maximumBitmapResolution)
- commandUnderTest.run(canvasUnderTest!!, layerModel!!)
- Assert.assertTrue("bitmap must not change if X left is larger than bitmap scope", originalBitmap.sameAs(layerUnderTest!!.bitmap))
+ commandUnderTest.run(canvasUnderTest, layerModel)
+ Assert.assertTrue("bitmap must not change if X left is larger than bitmap scope", originalBitmap.sameAs(
+ layerUnderTest.bitmap))
commandUnderTest = CropCommand(-1, 0, -1, 0, maximumBitmapResolution)
- commandUnderTest.run(canvasUnderTest!!, layerModel!!)
- Assert.assertTrue("bitmap must not change if X right is smaller than bitmap scope", originalBitmap.sameAs(layerUnderTest!!.bitmap))
- commandUnderTest = CropCommand(0, bitmapUnderTest!!.height, 0,
- bitmapUnderTest!!.height, maximumBitmapResolution)
- commandUnderTest.run(canvasUnderTest!!, layerModel!!)
- Assert.assertTrue("bitmap must not change if Y top is larger than bitmap scope", originalBitmap.sameAs(layerUnderTest!!.bitmap))
+ commandUnderTest.run(canvasUnderTest, layerModel)
+ Assert.assertTrue("bitmap must not change if X right is smaller than bitmap scope", originalBitmap.sameAs(
+ layerUnderTest.bitmap))
+ commandUnderTest = CropCommand(0, bitmapUnderTest.height, 0,
+ bitmapUnderTest.height, maximumBitmapResolution)
+ commandUnderTest.run(canvasUnderTest, layerModel)
+ Assert.assertTrue("bitmap must not change if Y top is larger than bitmap scope", originalBitmap.sameAs(
+ layerUnderTest.bitmap))
commandUnderTest = CropCommand(0, -1, 0, -1, maximumBitmapResolution)
- commandUnderTest.run(canvasUnderTest!!, layerModel!!)
- Assert.assertTrue("bitmap must not change if Y bottom is smaller than bitmap scope", originalBitmap.sameAs(layerUnderTest!!.bitmap))
+ commandUnderTest.run(canvasUnderTest, layerModel)
+ Assert.assertTrue("bitmap must not change if Y bottom is smaller than bitmap scope", originalBitmap.sameAs(
+ layerUnderTest.bitmap))
commandUnderTest = CropCommand(1, 0, 0, 0, maximumBitmapResolution)
- commandUnderTest.run(canvasUnderTest!!, layerModel!!)
- Assert.assertTrue("bitmap must not change with widthXRight < widthXLeft bound", originalBitmap.sameAs(layerUnderTest!!.bitmap))
+ commandUnderTest.run(canvasUnderTest, layerModel)
+ Assert.assertTrue("bitmap must not change with widthXRight < widthXLeft bound", originalBitmap.sameAs(
+ layerUnderTest.bitmap))
commandUnderTest = CropCommand(0, 1, 0, 0, maximumBitmapResolution)
- commandUnderTest.run(canvasUnderTest!!, layerModel!!)
- Assert.assertTrue("bitmap must not change with widthYBottom < widthYTop bound", originalBitmap.sameAs(layerUnderTest!!.bitmap))
- commandUnderTest = CropCommand(0, 0, bitmapUnderTest!!.width - 1,
- bitmapUnderTest!!.height - 1, maximumBitmapResolution)
- commandUnderTest.run(canvasUnderTest!!, layerModel!!)
- Assert.assertTrue("bitmap must not change because bounds are the same as original bitmap", originalBitmap.sameAs(layerUnderTest!!.bitmap))
+ commandUnderTest.run(canvasUnderTest, layerModel)
+ Assert.assertTrue("bitmap must not change with widthYBottom < widthYTop bound", originalBitmap.sameAs(
+ layerUnderTest.bitmap))
+ commandUnderTest = CropCommand(0, 0, bitmapUnderTest.width - 1,
+ bitmapUnderTest.height - 1, maximumBitmapResolution)
+ commandUnderTest.run(canvasUnderTest, layerModel)
+ Assert.assertTrue("bitmap must not change because bounds are the same as original bitmap", originalBitmap.sameAs(
+ layerUnderTest.bitmap))
}
companion object {
diff --git a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/FlipCommandTest.kt b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/FlipCommandTest.kt
index fc837defb0..5758ee19a0 100644
--- a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/FlipCommandTest.kt
+++ b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/FlipCommandTest.kt
@@ -53,18 +53,18 @@ class FlipCommandTest {
@Test
fun testVerticalFlip() {
commandUnderTest = FlipCommand(FlipDirection.FLIP_VERTICAL)
- bitmapUnderTest!!.setPixel(0, INITIAL_HEIGHT / 2, PAINT_BASE_COLOR)
+ bitmapUnderTest.setPixel(0, INITIAL_HEIGHT / 2, PAINT_BASE_COLOR)
commandUnderTest.run(canvasUnderTest!!, layerModel!!)
- val pixel = bitmapUnderTest!!.getPixel(INITIAL_WIDTH - 1, INITIAL_WIDTH / 2)
+ val pixel = bitmapUnderTest.getPixel(INITIAL_WIDTH - 1, INITIAL_WIDTH / 2)
Assert.assertEquals(PAINT_BASE_COLOR.toLong(), pixel.toLong())
}
@Test
fun testHorizontalFlip() {
commandUnderTest = FlipCommand(FlipDirection.FLIP_HORIZONTAL)
- bitmapUnderTest!!.setPixel(INITIAL_WIDTH / 2, 0, PAINT_BASE_COLOR)
+ bitmapUnderTest.setPixel(INITIAL_WIDTH / 2, 0, PAINT_BASE_COLOR)
commandUnderTest.run(canvasUnderTest!!, layerModel!!)
- val pixel = bitmapUnderTest!!.getPixel(INITIAL_WIDTH / 2, INITIAL_WIDTH - 1)
+ val pixel = bitmapUnderTest.getPixel(INITIAL_WIDTH / 2, INITIAL_WIDTH - 1)
Assert.assertEquals(PAINT_BASE_COLOR.toLong(), pixel.toLong())
}
diff --git a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/MergeLayersCommandTest.kt b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/MergeLayersCommandTest.kt
index 7dcdb3c100..c4a754cccc 100644
--- a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/MergeLayersCommandTest.kt
+++ b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/MergeLayersCommandTest.kt
@@ -74,10 +74,10 @@ class MergeLayersCommandTest {
@Test
fun testRun() {
commandUnderTest.run(canvasUnderTest, layerModel)
- Assert.assertEquals(layerModel.getLayerAt(0)!!.bitmap!!.getPixel(5, 5), PAINT_BASE_COLOR)
- Assert.assertEquals(layerModel.getLayerAt(0)!!.bitmap!!.getPixel(8, 8), PAINT_BASE_COLOR)
- Assert.assertEquals(layerModel.getLayerAt(0)!!.bitmap!!.getPixel(3, 3), 0)
- Assert.assertEquals(layerModel.getLayerAt(0)!!.bitmap!!.getPixel(0, 0), 0)
+ Assert.assertEquals(layerModel.getLayerAt(0)!!.bitmap.getPixel(5, 5), PAINT_BASE_COLOR)
+ Assert.assertEquals(layerModel.getLayerAt(0)!!.bitmap.getPixel(8, 8), PAINT_BASE_COLOR)
+ Assert.assertEquals(layerModel.getLayerAt(0)!!.bitmap.getPixel(3, 3), 0)
+ Assert.assertEquals(layerModel.getLayerAt(0)!!.bitmap.getPixel(0, 0), 0)
}
@Test
@@ -92,10 +92,10 @@ class MergeLayersCommandTest {
fun testRunMergeSeparatedLayers() {
commandUnderTest = MergeLayersCommand(2, 0)
commandUnderTest.run(canvasUnderTest, layerModel)
- Assert.assertEquals(layerModel.currentLayer!!.bitmap!!.getPixel(0, 0), PAINT_BASE_COLOR)
- Assert.assertEquals(layerModel.currentLayer!!.bitmap!!.getPixel(8, 8), PAINT_BASE_COLOR)
- Assert.assertEquals(layerModel.currentLayer!!.bitmap!!.getPixel(3, 3), 0)
- Assert.assertEquals(layerModel.currentLayer!!.bitmap!!.getPixel(5, 5), 0)
- Assert.assertEquals(layerModel.getLayerAt(1)!!.bitmap!!.getPixel(5, 5), PAINT_BASE_COLOR)
+ Assert.assertEquals(layerModel.currentLayer!!.bitmap.getPixel(0, 0), PAINT_BASE_COLOR)
+ Assert.assertEquals(layerModel.currentLayer!!.bitmap.getPixel(8, 8), PAINT_BASE_COLOR)
+ Assert.assertEquals(layerModel.currentLayer!!.bitmap.getPixel(3, 3), 0)
+ Assert.assertEquals(layerModel.currentLayer!!.bitmap.getPixel(5, 5), 0)
+ Assert.assertEquals(layerModel.getLayerAt(1)!!.bitmap.getPixel(5, 5), PAINT_BASE_COLOR)
}
}
diff --git a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/PathCommandTest.kt b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/PathCommandTest.kt
index 507eb0749a..1ee5e3ed36 100644
--- a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/PathCommandTest.kt
+++ b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/PathCommandTest.kt
@@ -66,10 +66,10 @@ class PathCommandTest {
@Test
fun testPathOutOfBounds() {
val path = Path()
- val left = (canvasBitmapUnderTest!!.width + 50).toFloat()
- val top = (canvasBitmapUnderTest!!.height + 50).toFloat()
- val right = (canvasBitmapUnderTest!!.width + 100).toFloat()
- val bottom = (canvasBitmapUnderTest!!.height + 100).toFloat()
+ val left = (canvasBitmapUnderTest.width + 50).toFloat()
+ val top = (canvasBitmapUnderTest.height + 50).toFloat()
+ val right = (canvasBitmapUnderTest.width + 100).toFloat()
+ val bottom = (canvasBitmapUnderTest.height + 100).toFloat()
path.addRect(RectF(left, top, right, bottom), Path.Direction.CW)
commandUnderTest = PathCommand(paintUnderTest!!, path)
commandUnderTest.run(canvasUnderTest!!, LayerModel())
diff --git a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/PointCommandTest.kt b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/PointCommandTest.kt
index 78533fb97d..55a27af4d1 100644
--- a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/PointCommandTest.kt
+++ b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/junit/command/PointCommandTest.kt
@@ -63,17 +63,17 @@ class PointCommandTest {
@Test
fun testRun() {
- bitmapUnderTest!!.setPixel(pointUnderTest!!.x.toInt(), pointUnderTest!!.y.toInt(), paintUnderTest!!.color)
- commandUnderTest!!.run(canvasUnderTest!!, LayerModel())
- assertBitmapEquals(bitmapUnderTest!!, canvasBitmapUnderTest)
+ bitmapUnderTest.setPixel(pointUnderTest!!.x.toInt(), pointUnderTest!!.y.toInt(), paintUnderTest!!.color)
+ commandUnderTest.run(canvasUnderTest!!, LayerModel())
+ assertBitmapEquals(bitmapUnderTest, canvasBitmapUnderTest)
}
@Test
fun testRunOutOfBounds() {
- pointUnderTest = PointF((canvasBitmapUnderTest!!.height + 1).toFloat(), (canvasBitmapUnderTest!!.width + 1).toFloat())
+ pointUnderTest = PointF((canvasBitmapUnderTest.height + 1).toFloat(), (canvasBitmapUnderTest.width + 1).toFloat())
commandUnderTest = PointCommand(paintUnderTest!!, pointUnderTest!!)
commandUnderTest.run(canvasUnderTest!!, LayerModel())
- assertBitmapEquals(bitmapUnderTest!!, canvasBitmapUnderTest)
+ assertBitmapEquals(bitmapUnderTest, canvasBitmapUnderTest)
}
companion object {
diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/FileIO.kt b/Paintroid/src/main/java/org/catrobat/paintroid/FileIO.kt
index 432399538f..a61e19e3ac 100644
--- a/Paintroid/src/main/java/org/catrobat/paintroid/FileIO.kt
+++ b/Paintroid/src/main/java/org/catrobat/paintroid/FileIO.kt
@@ -115,7 +115,7 @@ object FileIO {
require(currentBitmap != null && !currentBitmap.isRecycled) { "Bitmap is invalid" }
if (compressFormat == CompressFormat.JPEG) {
val newBitmap =
- Bitmap.createBitmap(currentBitmap.width, currentBitmap.height, currentBitmap.config)
+ Bitmap.createBitmap(currentBitmap.width, currentBitmap.height, currentBitmap.config ?: Bitmap.Config.ARGB_8888)
val canvas = Canvas(newBitmap)
canvas.drawColor(Color.WHITE)
canvas.drawBitmap(currentBitmap, 0f, 0f, null)
diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt b/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt
index dffb83df93..23988489f8 100644
--- a/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt
+++ b/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt
@@ -21,6 +21,7 @@ package org.catrobat.paintroid
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
+import android.content.pm.PackageManager
import android.graphics.Color
import android.graphics.Paint
import android.graphics.PointF
@@ -810,7 +811,14 @@ class MainActivity : AppCompatActivity(), MainView, CommandListener {
}
}
- fun getVersionCode(): String = runCatching {
- packageManager.getPackageInfo(packageName, 0).versionName
+ fun getVersionName(): String = runCatching {
+ val pm = packageManager
+ val pkgInfo = if (Build.VERSION.SDK_INT >= 33) {
+ pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0))
+ } else {
+ @Suppress("DEPRECATION")
+ pm.getPackageInfo(packageName, 0)
+ }
+ pkgInfo.versionName ?: ""
}.getOrDefault("")
}
diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/ClippingCommand.kt b/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/ClippingCommand.kt
index 2ebf7f70e8..c38a393cf5 100644
--- a/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/ClippingCommand.kt
+++ b/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/ClippingCommand.kt
@@ -12,8 +12,8 @@ import org.catrobat.paintroid.contract.LayerContracts
class ClippingCommand(bitmap: Bitmap, pathBitmap: Bitmap) : Command {
- var bitmap: Bitmap? = bitmap.copy(bitmap.config, true); private set
- var pathBitmap: Bitmap? = pathBitmap.copy(pathBitmap.config, true); private set
+ var bitmap: Bitmap? = bitmap.copy(bitmap.config ?: Bitmap.Config.ARGB_8888, true); private set
+ var pathBitmap: Bitmap? = pathBitmap.copy(pathBitmap.config ?: Bitmap.Config.ARGB_8888, true); private set
override fun run(canvas: Canvas, layerModel: LayerContracts.Model) {
val bitmapToDraw = bitmap
diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/CropCommand.kt b/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/CropCommand.kt
index 874d249ad7..58eb0bbd4f 100644
--- a/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/CropCommand.kt
+++ b/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/CropCommand.kt
@@ -57,7 +57,7 @@ class CropCommand(
while (iterator.hasNext()) {
val currentLayer = iterator.next()
val currentBitmap = currentLayer.bitmap ?: Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
- val resizedBitmap = Bitmap.createBitmap(width, height, currentBitmap.config)
+ val resizedBitmap = Bitmap.createBitmap(width, height, currentBitmap.config ?: Bitmap.Config.ARGB_8888)
val resizedCanvas = Canvas(resizedBitmap)
resizedCanvas.drawBitmap(currentBitmap, -resizeCoordinateXLeft.toFloat(), -resizeCoordinateYTop.toFloat(), null)
currentLayer.bitmap = resizedBitmap
diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/FlipCommand.kt b/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/FlipCommand.kt
index aefd9a5dcf..ea930150c6 100644
--- a/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/FlipCommand.kt
+++ b/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/FlipCommand.kt
@@ -19,6 +19,7 @@
package org.catrobat.paintroid.command.implementation
+import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Matrix
@@ -44,7 +45,7 @@ class FlipCommand(flipDirection: FlipDirection) : Command {
}
}
layerModel.currentLayer?.bitmap?.let { bitmap ->
- val bitmapCopy = bitmap.copy(bitmap.config, bitmap.isMutable)
+ val bitmapCopy = bitmap.copy(bitmap.config ?: Bitmap.Config.ARGB_8888, bitmap.isMutable)
val flipCanvas = Canvas(bitmap)
bitmap.eraseColor(Color.TRANSPARENT)
flipCanvas.drawBitmap(bitmapCopy, flipMatrix, Paint())
diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/MergeLayersCommand.kt b/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/MergeLayersCommand.kt
index c4b43491f6..e4b579681b 100644
--- a/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/MergeLayersCommand.kt
+++ b/Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/MergeLayersCommand.kt
@@ -19,6 +19,7 @@
package org.catrobat.paintroid.command.implementation
+import android.graphics.Bitmap
import android.graphics.Canvas
import android.util.Log
import org.catrobat.paintroid.command.Command
@@ -40,7 +41,7 @@ class MergeLayersCommand(position: Int, mergeWith: Int) : Command {
if (sourceLayer != null && destinationLayer != null) {
val destinationBitmap = destinationLayer.bitmap
destinationBitmap ?: return
- val copyBitmap = destinationBitmap.copy(destinationBitmap.config, true)
+ val copyBitmap = destinationBitmap.copy(destinationBitmap.config ?: Bitmap.Config.ARGB_8888, true)
val copyCanvas = Canvas(copyBitmap)
copyCanvas.drawBitmap(sourceLayer.bitmap ?: return, 0f, 0f, null)
if (layerModel.removeLayerAt(position)) {
diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AboutDialog.kt b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AboutDialog.kt
index d6a44a777c..aeae3ec679 100644
--- a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AboutDialog.kt
+++ b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AboutDialog.kt
@@ -52,7 +52,7 @@ class AboutDialog : AppCompatDialogFragment() {
val aboutLicenseView = view.findViewById(R.id.pocketpaint_about_license_url)
val aboutCatrobatView = view.findViewById(R.id.pocketpaint_about_catrobat_url)
val activity = requireActivity() as MainActivity
- val aboutVersion = getString(R.string.pocketpaint_about_version, activity.getVersionCode())
+ val aboutVersion = getString(R.string.pocketpaint_about_version, activity.getVersionName())
aboutVersionView.text = aboutVersion
val aboutContent = getString(
R.string.pocketpaint_about_content,
diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/tools/implementation/DefaultContextCallback.kt b/Paintroid/src/main/java/org/catrobat/paintroid/tools/implementation/DefaultContextCallback.kt
index b963cff2ba..a173bf305a 100644
--- a/Paintroid/src/main/java/org/catrobat/paintroid/tools/implementation/DefaultContextCallback.kt
+++ b/Paintroid/src/main/java/org/catrobat/paintroid/tools/implementation/DefaultContextCallback.kt
@@ -37,7 +37,7 @@ import androidx.annotation.StringRes
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
-import org.catrobat.paintroid.R
+import org.catrobat.paintroid.colorpicker.R
import org.catrobat.paintroid.tools.ContextCallback
import org.catrobat.paintroid.tools.ContextCallback.NotificationDuration
import org.catrobat.paintroid.tools.ContextCallback.NotificationDuration.SHORT
diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/tools/implementation/DefaultToolPaint.kt b/Paintroid/src/main/java/org/catrobat/paintroid/tools/implementation/DefaultToolPaint.kt
index 230792c5d9..99909d9c22 100644
--- a/Paintroid/src/main/java/org/catrobat/paintroid/tools/implementation/DefaultToolPaint.kt
+++ b/Paintroid/src/main/java/org/catrobat/paintroid/tools/implementation/DefaultToolPaint.kt
@@ -27,7 +27,7 @@ import android.graphics.Paint.Cap
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.graphics.Shader
-import org.catrobat.paintroid.R
+import org.catrobat.paintroid.colorpicker.R
import org.catrobat.paintroid.tools.ToolPaint
const val STROKE_25 = 25f
diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/ui/tools/BrushToolView.kt b/Paintroid/src/main/java/org/catrobat/paintroid/ui/tools/BrushToolView.kt
index f5bb3c6542..74efedfbaa 100644
--- a/Paintroid/src/main/java/org/catrobat/paintroid/ui/tools/BrushToolView.kt
+++ b/Paintroid/src/main/java/org/catrobat/paintroid/ui/tools/BrushToolView.kt
@@ -27,7 +27,7 @@ import android.graphics.Paint
import android.graphics.Shader
import android.util.AttributeSet
import android.view.View
-import org.catrobat.paintroid.R
+import org.catrobat.paintroid.colorpicker.R
import org.catrobat.paintroid.tools.ToolType
import org.catrobat.paintroid.tools.options.BrushToolOptionsView.OnBrushPreviewListener
import org.catrobat.paintroid.tools.options.BrushToolPreview
diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/web/MediaGalleryWebViewClient.java b/Paintroid/src/main/java/org/catrobat/paintroid/web/MediaGalleryWebViewClient.java
index 4690e2aa6e..dbc72a31aa 100644
--- a/Paintroid/src/main/java/org/catrobat/paintroid/web/MediaGalleryWebViewClient.java
+++ b/Paintroid/src/main/java/org/catrobat/paintroid/web/MediaGalleryWebViewClient.java
@@ -22,34 +22,36 @@
*/
package org.catrobat.paintroid.web;
-import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.webkit.WebView;
import android.webkit.WebViewClient;
-
-import org.catrobat.paintroid.R;
+import android.net.Uri;
+import android.view.View;
+import android.webkit.WebResourceError;
+import android.webkit.WebResourceRequest;
+import androidx.appcompat.app.AlertDialog;
+import androidx.core.view.ViewCompat;
+import android.widget.ProgressBar;
public class MediaGalleryWebViewClient extends WebViewClient {
- private ProgressDialog webViewLoadingDialog;
- private WebClientCallback callback;
+ private AlertDialog loadingDialog;
+ private final WebClientCallback callback;
public interface WebClientCallback {
void finish();
}
public MediaGalleryWebViewClient(WebClientCallback callback) {
- super();
this.callback = callback;
}
+ private static final String GALLERY_ROOT = "https://share.catrob.at/pocketcode/";
+
@Override
- public void onPageStarted(WebView view, String urlClient, Bitmap favicon) {
- if (webViewLoadingDialog == null && !urlClient.matches("https://share.catrob.at/pocketcode/")) {
- webViewLoadingDialog = new ProgressDialog(view.getContext(), R.style.WebViewLoadingCircle);
- webViewLoadingDialog.setCancelable(true);
- webViewLoadingDialog.setCanceledOnTouchOutside(false);
- webViewLoadingDialog.setProgressStyle(android.R.style.Widget_ProgressBar_Small);
- webViewLoadingDialog.show();
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ // avoid regex 'matches' – we only want a prefix check
+ if (!startsWithGalleryRoot(url)) {
+ showLoading(view);
} else {
callback.finish();
}
@@ -57,19 +59,71 @@ public void onPageStarted(WebView view, String urlClient, Bitmap favicon) {
@Override
public void onPageFinished(WebView view, String url) {
- if (webViewLoadingDialog != null) {
- webViewLoadingDialog.dismiss();
- webViewLoadingDialog = null;
- }
+ dismissLoading();
}
+ // New API (M+) — preferred
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
+ // Return false to let the WebView load the URL
+ return false;
+ }
+
+ // Legacy shim for < M
+ @SuppressWarnings("deprecation")
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}
+ // New API (M+) — preferred
+ @Override
+ public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+ dismissLoading();
+ callback.finish();
+ }
+
+ // Legacy shim for < M
+ @SuppressWarnings("deprecation")
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+ dismissLoading();
callback.finish();
}
+
+ private boolean startsWithGalleryRoot(String url) {
+ try {
+ Uri u = Uri.parse(url);
+ // normalize to compare robustly
+ String normalized = u.getScheme() + "://" + u.getHost() + (u.getPort() != -1 ? (":" + u.getPort()) : "") + u.getPath();
+ return normalized.startsWith(GALLERY_ROOT);
+ } catch (Exception ignored) {
+ return false;
+ }
+ }
+
+ private void showLoading(View anchor) {
+ if (loadingDialog != null) return;
+
+ ProgressBar progress = new ProgressBar(anchor.getContext());
+ // make it large enough and accessible
+ int padding = (int) (anchor.getResources().getDisplayMetrics().density * 24);
+ progress.setPadding(padding, padding, padding, padding);
+ ViewCompat.setImportantForAccessibility(progress, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
+
+ loadingDialog = new AlertDialog.Builder(anchor.getContext())
+ .setView(progress)
+ .setCancelable(true)
+ .create();
+ loadingDialog.setCanceledOnTouchOutside(false);
+ loadingDialog.show();
+ }
+
+ private void dismissLoading() {
+ if (loadingDialog != null) {
+ loadingDialog.dismiss();
+ loadingDialog = null;
+ }
+ }
}
+
diff --git a/app/build.gradle b/app/build.gradle
index 2c7e76738b..0aa6689eab 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -19,42 +19,48 @@ import io.gitlab.arturbosch.detekt.Detekt
* along with this program. If not, see .
*/
-apply plugin: 'com.android.application'
+plugins {
+ id "com.android.application"
+ id "org.jetbrains.kotlin.android"
+}
ext {
- appId = 'org.catrobat.paintroid'
- appName = '@string/pocketpaint_app_name'
+ appId = "org.catrobat.paintroid"
+ appName = "@string/pocketpaint_app_name"
}
-// When -Pindependent was provided on the gradle command the APP name is changed.
-// This allows to have multiple Paintroid versions installed in parallel for testing purposes.
-// Furthermore these installations do not interfere with the actual Paintroid app.
-if (project.hasProperty('independent')) {
+// Allow multiple side-by-side installs when run with -Pindependent
+if (project.hasProperty("independent")) {
def today = new Date()
- appId += '.independent_' + today.format('YYYYMMdd_HHmm')
- appName = property('independent') ?: 'Paint ' + today.format('MMdd HH:mm')
+ appId += ".independent_${today.format('yyyyMMdd_HHmm')}"
+ appName = property("independent") ?: "Paint ${today.format('MMdd HH:mm')}"
}
+// Provide a dummy keystore if none is passed
if (!project.hasProperty("signingKeystore")) {
ext.signingKeystore = "dummyKeystore"
}
android {
- compileSdkVersion rootProject.ext.androidCompileSdkVersion
+ namespace "org.catrobat.paintroid.app"
+ compileSdk = rootProject.ext.androidCompileSdkVersion
+
defaultConfig {
applicationId appId
- minSdkVersion rootProject.ext.androidMinSdkVersion
- //noinspection OldTargetApi
- targetSdkVersion rootProject.ext.androidTargetSdkVersion
- versionCode rootProject.ext.androidVersionCode
- versionName rootProject.ext.androidVersionName
+ minSdk = rootProject.ext.androidMinSdkVersion
+ targetSdk = rootProject.ext.androidTargetSdkVersion
+ versionCode = rootProject.ext.androidVersionCode
+ versionName = rootProject.ext.androidVersionName
manifestPlaceholders += [appName: appName]
setProperty("archivesBaseName", "paintroid")
}
compileOptions {
- sourceCompatibility JavaVersion.VERSION_11
- targetCompatibility JavaVersion.VERSION_11
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ kotlinOptions {
+ jvmTarget = "17"
}
signingConfigs {
@@ -66,40 +72,48 @@ android {
}
}
- if (project.hasProperty("signingKeystore") && project.hasProperty("signingKeystorePassword") &&
- project.hasProperty("signingKeyAlias") && project.hasProperty("signingKeyPassword")) {
- android.signingConfigs.signedRelease.storePassword = project.property("signingKeystorePassword")
- android.signingConfigs.signedRelease.keyAlias = project.property("signingKeyAlias")
- android.signingConfigs.signedRelease.keyPassword = project.property("signingKeyPassword")
+ if (project.hasProperty("signingKeystore") &&
+ project.hasProperty("signingKeystorePassword") &&
+ project.hasProperty("signingKeyAlias") &&
+ project.hasProperty("signingKeyPassword")) {
+
+ signingConfigs.signedRelease.storePassword = project.property("signingKeystorePassword")
+ signingConfigs.signedRelease.keyAlias = project.property("signingKeyAlias")
+ signingConfigs.signedRelease.keyPassword = project.property("signingKeyPassword")
}
buildTypes {
release {
minifyEnabled true
shrinkResources true
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
- signedRelease.initWith(buildTypes.release)
- signedRelease {
- signingConfig signingConfigs.signedRelease
+ create("signedRelease") {
+ initWith(buildTypes.release)
+ signingConfig = signingConfigs.signedRelease
}
}
publishing {
- singleVariant('release') {
+ singleVariant("release") {
withSourcesJar()
}
}
+ packaging {
+ jniLibs {
+ useLegacyPackaging false
+ }
+ }
}
-tasks.withType(Detekt).configureEach {
- jvmTarget = "1.8"
+tasks.withType(io.gitlab.arturbosch.detekt.Detekt).configureEach {
+ jvmTarget = "17"
exclude("**/resources/**")
exclude("**/build/**")
}
dependencies {
- implementation project(':Paintroid')
-
- implementation 'com.android.support:support-core-utils:28.0.0'
+ implementation project(":Paintroid")
+ implementation "com.android.support:support-core-utils:28.0.0"
}
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4ffe27c5a3..7811fe1b30 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -21,11 +21,16 @@
xmlns:tools="http://schemas.android.com/tools"
package="org.catrobat.paintroid.app">
+
+
+
+
+ android:resource="@xml/filepaths" />
.
*/
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.7.10'
+ ext.kotlin_version = '1.9.24'
repositories {
- mavenCentral()
google()
+ mavenCentral()
maven { url "https://plugins.gradle.org/m2/" }
maven { url 'https://jitpack.io' }
}
dependencies {
- classpath 'com.android.tools.build:gradle:7.2.1'
- classpath 'com.hiya:jacoco-android:0.2'
classpath 'com.github.Catrobat:Gradle:1.6.2'
- classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:3.1.0'
- classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.20.0"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
plugins {
- id "io.gitlab.arturbosch.detekt" version "1.20.0"
+ id "com.android.application" version '8.13.0' apply false
+ id "com.android.library" version '8.13.0' apply false
+ id "org.jetbrains.kotlin.android" version "1.9.24" apply false
+ id "io.gitlab.arturbosch.detekt" version "1.23.6" apply false
+ id "com.getkeepsafe.dexcount" version "4.0.0" apply false
}
ext {
- androidCompileSdkVersion = 34
+ androidCompileSdkVersion = 35
+ androidTargetSdkVersion = 35
androidMinSdkVersion = 21
- androidTargetSdkVersion = 34
androidSupportLibraryVersion = '28.0.0'
diff --git a/colorpicker/build.gradle b/colorpicker/build.gradle
index e1f8ea1e11..3af101c7a4 100644
--- a/colorpicker/build.gradle
+++ b/colorpicker/build.gradle
@@ -21,23 +21,22 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
+ namespace "org.catrobat.paintroid.colorpicker"
compileSdkVersion rootProject.ext.androidCompileSdkVersion
defaultConfig {
minSdkVersion rootProject.ext.androidMinSdkVersion
targetSdkVersion rootProject.ext.androidTargetSdkVersion
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
- versionCode rootProject.ext.androidVersionCode
- versionName rootProject.ext.androidVersionName
}
compileOptions {
- sourceCompatibility JavaVersion.VERSION_11
- targetCompatibility JavaVersion.VERSION_11
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
- jvmTarget = JavaVersion.VERSION_11.toString()
+ jvmTarget = "17"
}
buildTypes {
@@ -57,4 +56,4 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
-}
+}
\ No newline at end of file
diff --git a/colorpicker/src/main/java/org/catrobat/paintroid/colorpicker/ColorPickerPresetColorButton.kt b/colorpicker/src/main/java/org/catrobat/paintroid/colorpicker/ColorPickerPresetColorButton.kt
index 7176cabef7..f072acf183 100644
--- a/colorpicker/src/main/java/org/catrobat/paintroid/colorpicker/ColorPickerPresetColorButton.kt
+++ b/colorpicker/src/main/java/org/catrobat/paintroid/colorpicker/ColorPickerPresetColorButton.kt
@@ -32,7 +32,7 @@ class ColorPickerPresetColorButton @JvmOverloads constructor(
context: Context,
@field:ColorInt @get:ColorInt
@param:ColorInt var color: Int = Color.BLACK
-) : AppCompatImageButton(context, null, R.attr.borderlessButtonStyle) {
+) : AppCompatImageButton(context, null, android.R.attr.borderlessButtonStyle) {
init {
val checkeredBitmap =
diff --git a/gradle.properties b/gradle.properties
index 5e9758afa7..d91fa61429 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,4 +1,4 @@
android.enableJetifier=true
android.useAndroidX=true
-org.gradle.jvmargs=-XX:MaxPermSize=1024m -Xmx4096m
-android.disableAutomaticComponentCreation=true
\ No newline at end of file
+org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8
+android.nonTransitiveRClass=false
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index eb250c9aae..af685a4a17 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Feb 02 16:23:53 CET 2021
+#Thu Sep 04 16:50:59 CEST 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
diff --git a/settings.gradle b/settings.gradle
index ee2027bde3..da41808e20 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -17,4 +17,26 @@
* along with this program. If not, see .
*/
-include ':Paintroid', ':app', ':colorpicker'
+// settings.gradle (Groovy)
+
+pluginManagement {
+ repositories {
+ google() // needed for com.android.application / com.android.library
+ mavenCentral()
+ gradlePluginPortal() // Gradle Central Plugin Repository
+ }
+}
+
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.PREFER_PROJECT)
+ repositories {
+ google()
+ mavenCentral()
+ mavenLocal()
+ }
+}
+
+rootProject.name = "Paintroid"
+
+include(":Paintroid", ":app", ":colorpicker")
+