diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..b75dee8
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,16 @@
+* text=auto eol=lf
+
+*.bat text eol=crlf
+*.cmd text eol=crlf
+*.ps1 text eol=crlf
+
+*.png binary
+*.jpg binary
+*.jpeg binary
+*.gif binary
+*.webp binary
+*.ico binary
+*.keystore binary
+*.jks binary
+*.zip binary
+*.jar binary
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8853ba0..dd04359 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,7 +2,12 @@
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/mba/vm/onhit/Constant.kt b/app/src/main/java/mba/vm/onhit/Constant.kt
index 41da603..fb89a7e 100644
--- a/app/src/main/java/mba/vm/onhit/Constant.kt
+++ b/app/src/main/java/mba/vm/onhit/Constant.kt
@@ -13,6 +13,8 @@ class Constant {
const val PREF_FIXED_UID = "pref_fixed_uid"
const val PREF_FIXED_UID_VALUE = "pref_fixed_uid_value"
const val PREF_RANDOM_UID_LEN = "pref_random_uid_len"
+
+ const val PREF_BACKGROUND_URI = "pref_background_uri"
const val MAX_OF_BROADCAST_SIZE = 1048576
const val GITHUB_URL = "https://github.com/0penPublic/onHit"
diff --git a/app/src/main/java/mba/vm/onhit/core/ConfigManager.kt b/app/src/main/java/mba/vm/onhit/core/ConfigManager.kt
index de022c2..1033977 100644
--- a/app/src/main/java/mba/vm/onhit/core/ConfigManager.kt
+++ b/app/src/main/java/mba/vm/onhit/core/ConfigManager.kt
@@ -10,6 +10,7 @@ import mba.vm.onhit.Constant.Companion.SHARED_PREFERENCES_CHOSEN_FOLDER
import mba.vm.onhit.Constant.Companion.SHARED_PREFERENCES_NAME
import mba.vm.onhit.utils.HexUtils
import java.security.SecureRandom
+import mba.vm.onhit.Constant.Companion.PREF_BACKGROUND_URI
object ConfigManager {
fun getRootUri(context: Context): Uri? {
@@ -47,11 +48,27 @@ object ConfigManager {
.getString(PREF_RANDOM_UID_LEN, "4") ?: "4"
}
+
fun setRandomUidLen(context: Context, len: String) {
context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
.edit().putString(PREF_RANDOM_UID_LEN, len).apply()
}
+
+ fun getBackgroundUri(context: Context): Uri? {
+ val value = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
+ .getString(PREF_BACKGROUND_URI, null)
+ return if (value.isNullOrEmpty()) null else Uri.parse(value)
+ }
+
+ fun setBackgroundUri(context: Context, uri: Uri?) {
+ context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
+ .edit().apply {
+ if (uri == null) remove(PREF_BACKGROUND_URI)
+ else putString(PREF_BACKGROUND_URI, uri.toString())
+ }.apply()
+ }
+
fun getUid(context: Context): ByteArray {
if (isFixedUid(context)) {
val hex = getFixedUidValue(context)
diff --git a/app/src/main/java/mba/vm/onhit/helper/DialogHelper.kt b/app/src/main/java/mba/vm/onhit/helper/DialogHelper.kt
index d4266c8..d3f3b32 100644
--- a/app/src/main/java/mba/vm/onhit/helper/DialogHelper.kt
+++ b/app/src/main/java/mba/vm/onhit/helper/DialogHelper.kt
@@ -113,7 +113,14 @@ object DialogHelper {
return dialog
}
- fun showSettingsSheet(context: Context, onChangeDir: () -> Unit) {
+ fun showSettingsSheet(
+ context: Context,
+ onChangeDir: () -> Unit,
+ onChangeBackground: () -> Unit,
+ onClearBackground: () -> Unit
+ )
+
+ {
val dialog = createBottomDialog(context, R.layout.bottom_sheet_settings)
val btnChangeDir = dialog.findViewById(R.id.btn_change_dir)
@@ -122,6 +129,34 @@ object DialogHelper {
val uidConfigSummary = dialog.findViewById(R.id.tv_uid_config_summary)
val etUidConfig = dialog.findViewById(R.id.et_uid_config)
+ val btnChangeBackground = dialog.findViewById(R.id.btn_change_background)
+ val btnClearBackground = dialog.findViewById(R.id.btn_clear_background)
+ val backgroundSummary = dialog.findViewById(R.id.tv_background_summary)
+
+ backgroundSummary.text =
+ if (ConfigManager.getBackgroundUri(context) == null) {
+ context.getString(R.string.settings_background_default)
+ } else {
+ context.getString(R.string.settings_background_custom)
+ }
+
+ btnChangeBackground.setOnClickListener {
+ dialog.dismiss()
+ onChangeBackground()
+ }
+
+ btnClearBackground.setOnClickListener {
+
+ ConfigManager.setBackgroundUri(context, null)
+
+ backgroundSummary.text =
+ context.getString(R.string.settings_background_default)
+
+ dialog.dismiss()
+
+ onClearBackground()
+ }
+
btnChangeDir.setOnClickListener {
dialog.dismiss()
onChangeDir()
diff --git a/app/src/main/java/mba/vm/onhit/ui/MainActivity.kt b/app/src/main/java/mba/vm/onhit/ui/MainActivity.kt
index e314041..a764f4c 100644
--- a/app/src/main/java/mba/vm/onhit/ui/MainActivity.kt
+++ b/app/src/main/java/mba/vm/onhit/ui/MainActivity.kt
@@ -17,7 +17,6 @@ import android.window.OnBackInvokedDispatcher
import androidx.core.content.IntentCompat
import androidx.core.view.WindowCompat
import androidx.documentfile.provider.DocumentFile
-import mba.vm.onhit.BuildConfig
import mba.vm.onhit.Constant
import mba.vm.onhit.Constant.Companion.MAX_OF_BROADCAST_SIZE
import mba.vm.onhit.R
@@ -49,10 +48,18 @@ class MainActivity : Activity() {
private var pendingImportUri: Uri? = null
+ private val REQUEST_SELECT_BACKGROUND = 1002
+
+ private val REQUEST_CROP_BACKGROUND = 1003
+ private var pendingCroppedBackgroundUri: Uri? = null
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
+
+ applyCustomBackground()
+
handleIntent(intent)
WindowCompat.setDecorFitsSystemWindows(window, false)
@@ -78,7 +85,7 @@ class MainActivity : Activity() {
private fun handleIntent(intent: Intent?) {
val className = intent?.component?.className ?: return
- val appId = BuildConfig.APPLICATION_ID
+ val appId = packageName
when (className) {
"$appId.ImportHandler" -> {
val uri = if (intent.action == Intent.ACTION_SEND) {
@@ -177,7 +184,22 @@ class MainActivity : Activity() {
if (pendingImportUri != null) {
performImportSave()
} else {
- DialogHelper.showSettingsSheet(this) { requestSelectDirectory() }
+ DialogHelper.showSettingsSheet(
+ this,
+
+ {
+ requestSelectDirectory()
+ },
+
+ {
+ requestSelectBackground()
+ },
+
+ {
+ ConfigManager.setBackgroundUri(this, null)
+ applyCustomBackground()
+ }
+ )
}
}
@@ -222,7 +244,6 @@ class MainActivity : Activity() {
binding.tvAppTitle.visibility = View.GONE
binding.etSearch.visibility = View.VISIBLE
binding.etSearch.requestFocus()
- binding.etSearch.requestFocus()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
binding.etSearch.windowInsetsController?.show(WindowInsets.Type.ime())
} else {
@@ -436,6 +457,24 @@ class MainActivity : Activity() {
Toast.makeText(this, R.string.toast_storage_unavailable, Toast.LENGTH_SHORT).show()
}
}
+ } else if (requestCode == REQUEST_SELECT_BACKGROUND && resultCode == RESULT_OK) {
+ data?.data?.let { uri ->
+ try {
+ contentResolver.takePersistableUriPermission(
+ uri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ )
+ } catch (_: Exception) {
+ }
+
+ startCropBackground(uri)
+ }
+
+ } else if (requestCode == REQUEST_CROP_BACKGROUND && resultCode == RESULT_OK) {
+ pendingCroppedBackgroundUri?.let { uri ->
+ ConfigManager.setBackgroundUri(this, uri)
+ applyCustomBackground()
+ }
}
}
@@ -455,4 +494,115 @@ class MainActivity : Activity() {
super.onDestroy()
executor.shutdown()
}
+ private fun requestSelectBackground() {
+ val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
+ addCategory(Intent.CATEGORY_OPENABLE)
+ type = "image/*"
+ addFlags(
+ Intent.FLAG_GRANT_READ_URI_PERMISSION or
+ Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ )
+ }
+
+ startActivityForResult(intent, REQUEST_SELECT_BACKGROUND)
+ }
+
+ private fun startCropBackground(sourceUri: Uri) {
+ val outputFile = java.io.File(filesDir, "custom_background_cropped.jpg")
+
+ if (!outputFile.exists()) {
+ outputFile.createNewFile()
+ }
+
+ val outputUri = androidx.core.content.FileProvider.getUriForFile(
+ this,
+ "${packageName}.fileprovider",
+ outputFile
+ )
+
+ pendingCroppedBackgroundUri = outputUri
+
+ val cropIntent = Intent("com.android.camera.action.CROP").apply {
+ setDataAndType(sourceUri, "image/*")
+
+ putExtra("crop", "true")
+ putExtra("aspectX", 9)
+ putExtra("aspectY", 16)
+ putExtra("scale", true)
+ putExtra("return-data", false)
+
+ putExtra(android.provider.MediaStore.EXTRA_OUTPUT, outputUri)
+ putExtra("outputFormat", android.graphics.Bitmap.CompressFormat.JPEG.toString())
+
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
+
+ clipData = android.content.ClipData.newRawUri(
+ "cropped_background",
+ outputUri
+ )
+ }
+
+ val resInfoList = packageManager.queryIntentActivities(
+ cropIntent,
+ android.content.pm.PackageManager.MATCH_DEFAULT_ONLY
+ )
+
+ for (resolveInfo in resInfoList) {
+ val packageName = resolveInfo.activityInfo.packageName
+
+ grantUriPermission(
+ packageName,
+ sourceUri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ )
+
+ grantUriPermission(
+ packageName,
+ outputUri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ )
+ }
+
+ try {
+ startActivityForResult(cropIntent, REQUEST_CROP_BACKGROUND)
+ } catch (_: Exception) {
+ Toast.makeText(this, R.string.unknown_error, Toast.LENGTH_SHORT).show()
+
+ ConfigManager.setBackgroundUri(this, sourceUri)
+ applyCustomBackground()
+ }
+ }
+ private fun applyCustomBackground() {
+ val uri = ConfigManager.getBackgroundUri(this)
+
+ if (uri == null) {
+ binding.ivCustomBackground.setImageDrawable(null)
+ binding.ivCustomBackground.visibility = View.GONE
+ binding.vBackgroundScrim.visibility = View.GONE
+
+ binding.topBar.setBackgroundColor(
+ android.graphics.Color.TRANSPARENT
+ )
+
+ return
+ }
+
+ try {
+ binding.ivCustomBackground.setImageDrawable(null)
+ binding.ivCustomBackground.setImageURI(uri)
+
+ binding.ivCustomBackground.visibility = View.VISIBLE
+ binding.vBackgroundScrim.visibility = View.VISIBLE
+
+ binding.topBar.setBackgroundColor(
+ getColor(R.color.custom_panel_background)
+ )
+
+ } catch (_: Exception) {
+ Toast.makeText(this, R.string.unknown_error, Toast.LENGTH_SHORT).show()
+ ConfigManager.setBackgroundUri(this, null)
+ applyCustomBackground()
+ }
+ }
}
diff --git a/app/src/main/res/drawable-night/bg_file_item.xml b/app/src/main/res/drawable-night/bg_file_item.xml
new file mode 100644
index 0000000..7d9a7c9
--- /dev/null
+++ b/app/src/main/res/drawable-night/bg_file_item.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/baseline_delete_24.xml b/app/src/main/res/drawable/baseline_delete_24.xml
new file mode 100644
index 0000000..16e8b1b
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_delete_24.xml
@@ -0,0 +1,9 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_file_item.xml b/app/src/main/res/drawable/bg_file_item.xml
new file mode 100644
index 0000000..801f480
--- /dev/null
+++ b/app/src/main/res/drawable/bg_file_item.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 969eb5d..628c752 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -6,18 +6,36 @@
android:layout_height="match_parent"
android:fitsSystemWindows="true">
+
+
+
+
+ android:orientation="vertical"
+ android:background="@android:color/transparent">
+ android:paddingTop="18dp">
+ android:text="@string/app_name"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="24sp"
+ android:textStyle="bold" />
+ android:tint="?android:attr/textColorPrimary" />
+ android:tint="?android:attr/textColorPrimary" />
+ android:scrollbars="none">
+ android:layout_height="match_parent"
+ android:background="@android:color/transparent">
@@ -139,7 +159,7 @@
android:background="@drawable/bg_circle_icon"
android:src="@drawable/baseline_settings_24"
android:tint="?android:attr/textColorPrimary"
- android:backgroundTint="?android:attr/colorBackground"
+ android:backgroundTint="@color/custom_fab_background"
android:elevation="6dp"
android:contentDescription="@string/setting" />
diff --git a/app/src/main/res/layout/bottom_sheet_settings.xml b/app/src/main/res/layout/bottom_sheet_settings.xml
index d04f294..607c4c8 100644
--- a/app/src/main/res/layout/bottom_sheet_settings.xml
+++ b/app/src/main/res/layout/bottom_sheet_settings.xml
@@ -107,6 +107,78 @@
android:inputType=""
tools:ignore="LabelFor" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:background="@drawable/bg_file_item"
+ android:foreground="?android:attr/selectableItemBackground">
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-night/custom_background_colors.xml b/app/src/main/res/values-night/custom_background_colors.xml
new file mode 100644
index 0000000..2a4a5a0
--- /dev/null
+++ b/app/src/main/res/values-night/custom_background_colors.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ #11000000
+
+
+ #44000000
+
+
+ #00000000
+
+
+ #66000000
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml
index 80ad915..dc4e837 100644
--- a/app/src/main/res/values-zh/strings.xml
+++ b/app/src/main/res/values-zh/strings.xml
@@ -51,4 +51,10 @@
已导入: %s
导入失败: %s
将 %s 保存至…
+
+ 更换背景图片
+ 清除背景图片
+ 当前使用默认背景
+ 当前使用自定义背景
+ 未知错误
diff --git a/app/src/main/res/values/custom_background_colors.xml b/app/src/main/res/values/custom_background_colors.xml
new file mode 100644
index 0000000..486a308
--- /dev/null
+++ b/app/src/main/res/values/custom_background_colors.xml
@@ -0,0 +1,7 @@
+
+
+ #22FFFFFF
+ #AAFFFFFF
+ #66FFFFFF
+ #CCFFFFFF
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3b66e5e..e689f7b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -52,4 +52,10 @@
Import failed: %s
Save %s to…
+
+ Change background image
+ Clear background image
+ Using default background
+ Using custom background
+ unknown error
diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml
new file mode 100644
index 0000000..95149fc
--- /dev/null
+++ b/app/src/main/res/xml/file_paths.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/gradlew.bat b/gradlew.bat
index aa5f10b..24c62d5 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,82 +1,82 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-@rem SPDX-License-Identifier: Apache-2.0
-@rem
-
-@if "%DEBUG%"=="" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables, and ensure extensions are enabled
-setlocal EnableExtensions
-
-set DIRNAME=%~dp0
-if "%DIRNAME%"=="" set DIRNAME=.
-@rem This is normally unused
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if %ERRORLEVEL% equ 0 goto execute
-
-echo. 1>&2
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
-echo. 1>&2
-echo Please set the JAVA_HOME variable in your environment to match the 1>&2
-echo location of your Java installation. 1>&2
-
-"%COMSPEC%" /c exit 1
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto execute
-
-echo. 1>&2
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
-echo. 1>&2
-echo Please set the JAVA_HOME variable in your environment to match the 1>&2
-echo location of your Java installation. 1>&2
-
-"%COMSPEC%" /c exit 1
-
-:execute
-@rem Setup the command line
-
-
-
-@rem Execute Gradle
-@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
-@rem which allows us to clear the local environment before executing the java command
-endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
-
-:exitWithErrorLevel
-@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
-"%COMSPEC%" /c exit %ERRORLEVEL%
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables, and ensure extensions are enabled
+setlocal EnableExtensions
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+"%COMSPEC%" /c exit 1
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+"%COMSPEC%" /c exit 1
+
+:execute
+@rem Setup the command line
+
+
+
+@rem Execute Gradle
+@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
+@rem which allows us to clear the local environment before executing the java command
+endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
+
+:exitWithErrorLevel
+@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
+"%COMSPEC%" /c exit %ERRORLEVEL%