diff --git a/.gitignore b/.gitignore
index aa724b7..03a5ecb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,4 @@
.externalNativeBuild
.cxx
local.properties
+/.idea
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index 69e8615..5815a4a 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 6b0c3cf..ffa770c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,11 +1,13 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
+ id 'kotlin-android'
+ id 'kotlin-kapt'
}
android {
namespace 'com.zeusinstitute.upiapp'
- compileSdk 33
+ compileSdk 34
defaultConfig {
applicationId "com.zeusinstitute.upiapp"
@@ -48,7 +50,21 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1'
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
+
+
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+
+ def room_version = "2.5.2"
+
+ implementation "androidx.room:room-runtime:$room_version"
+ kapt "androidx.room:room-compiler:$room_version" // Use kapt instead of ksp
+
+ // optional - Test helpers
+ testImplementation "androidx.room:room-testing:$room_version"
+
+ // optional - Kotlin Extensions and Coroutines support for Room
+ implementation "androidx.room:room-ktx:$room_version"
+
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8de58be..c6e2db7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -20,7 +20,8 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.UPIAPP"
- tools:targetApi="18" >
+ tools:targetApi="18"
+ android:name=".UPIAPP">
+ adapter.submitList(transactions) // Update adapter on main thread
+ Log.d("BillHistory", "Fetched ${transactions.size} transactions")
+ }
+ }
+ return view
+ }
+ private fun exportTransactionsToXML(transactions: List) {
+ try {
+ val docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
+ val doc = docBuilder.newDocument()
+ val rootElement = doc.createElement("transactions")
+ doc.appendChild(rootElement)
+
+ transactions.forEach { transaction ->
+ val transactionElement = doc.createElement("transaction")
+ rootElement.appendChild(transactionElement)
+
+ val nameElement = doc.createElement("name")
+ nameElement.appendChild(doc.createTextNode(transaction.name))
+ transactionElement.appendChild(nameElement)
+
+ val typeElement = doc.createElement("type")
+ typeElement.appendChild(doc.createTextNode(transaction.type))
+ transactionElement.appendChild(typeElement)
+
+ val amountElement = doc.createElement("amount")
+ amountElement.appendChild(doc.createTextNode(transaction.amount.toString()))
+ transactionElement.appendChild(amountElement)
+
+ val dateElement = doc.createElement("date")
+ dateElement.appendChild(doc.createTextNode(transaction.date))
+ transactionElement.appendChild(dateElement)
+ }
+
+ val transformerFactory = TransformerFactory.newInstance()
+ val transformer = transformerFactory.newTransformer()
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes")
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2")
+
+ val writer = StringWriter()
+ transformer.transform(DOMSource(doc), StreamResult(writer))
+ val xmlString = writer.toString()
+
+ // TODO: Save the xmlString to a file or share it as needed
+ println(xmlString) // Print XML to console for now
+ } catch (e: Exception) {
+ // Handle exceptions during XML creation
+ e.printStackTrace()
+ }
+ }
+ private fun refreshData() {
+ val sharedPref = requireActivity().getPreferences(Context.MODE_PRIVATE)
+ val smsEnabled = sharedPref.getBoolean("sms_enabled", false)
+
+ warningTextView.visibility = if (smsEnabled) View.GONE else View.VISIBLE
+ if (!smsEnabled) {
+ warningTextView.text = "History Disabled, enable from Login."
+ return // Don't reload data if SMS is disabled
+ }
+
+ lifecycleScope.launch {
+ val db = (requireContext().applicationContext as UPIAPP).database // Get centralized database
+ val transactionDao = db.transactionDao()
+ val transactions = withContext(Dispatchers.IO) { transactionDao.getAllTransactionsOrderedByDate().first() }
+ adapter.submitList(transactions)
+ Log.d("BillHistory", "Fetched ${transactions.size} transactions")
+ if (transactions.isEmpty()) {
+ warningTextView.text = "No Data Available"
+ warningTextView.visibility = View.VISIBLE
+ } else {
+ warningTextView.text = ""
+ warningTextView.visibility = View.GONE
+ }
+ }
+ }
+}
+
diff --git a/app/src/main/java/com/zeusinstitute/upiapp/MIGRATION_1_2.kt b/app/src/main/java/com/zeusinstitute/upiapp/MIGRATION_1_2.kt
new file mode 100644
index 0000000..1c6893d
--- /dev/null
+++ b/app/src/main/java/com/zeusinstitute/upiapp/MIGRATION_1_2.kt
@@ -0,0 +1,10 @@
+package com.zeusinstitute.upiapp
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+val MIGRATION_1_2 = object : Migration(1, 2) {
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("ALTER TABLE PayTransaction ADD COLUMN name TEXT")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/zeusinstitute/upiapp/MainActivity.kt b/app/src/main/java/com/zeusinstitute/upiapp/MainActivity.kt
index cc659a4..5d3b357 100644
--- a/app/src/main/java/com/zeusinstitute/upiapp/MainActivity.kt
+++ b/app/src/main/java/com/zeusinstitute/upiapp/MainActivity.kt
@@ -77,6 +77,10 @@ class MainActivity : AppCompatActivity() {
findNavController(R.id.nav_host_fragment_content_main).navigate(R.id.action_firstFragment_to_splitBillFragment)
true
}
+ R.id.billHistory -> {
+ findNavController(R.id.nav_host_fragment_content_main).navigate(R.id.action_firstFragment_to_billHistory)
+ true
+ }
R.id.DynUPI -> {
findNavController(R.id.nav_host_fragment_content_main).navigate(R.id.action_firstFragment_to_dynamicFragment)
true
diff --git a/app/src/main/java/com/zeusinstitute/upiapp/PayTransaction.kt b/app/src/main/java/com/zeusinstitute/upiapp/PayTransaction.kt
new file mode 100644
index 0000000..b177848
--- /dev/null
+++ b/app/src/main/java/com/zeusinstitute/upiapp/PayTransaction.kt
@@ -0,0 +1,13 @@
+package com.zeusinstitute.upiapp
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+@Entity
+data class PayTransaction(
+ @PrimaryKey(autoGenerate = true) val id: Int = 0,
+ val name: String,
+ val amount: Double,
+ val type: String, // "Credit" or "Debit"
+ val date: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/zeusinstitute/upiapp/SMSService.kt b/app/src/main/java/com/zeusinstitute/upiapp/SMSService.kt
index 03efb89..6f34b51 100644
--- a/app/src/main/java/com/zeusinstitute/upiapp/SMSService.kt
+++ b/app/src/main/java/com/zeusinstitute/upiapp/SMSService.kt
@@ -18,6 +18,9 @@ import androidx.core.app.NotificationCompat
import java.util.*
import java.util.concurrent.LinkedBlockingQueue
import kotlinx.coroutines.*
+import androidx.room.*
+import java.text.SimpleDateFormat
+
class SMSService : Service(), TextToSpeech.OnInitListener {
private var tts: TextToSpeech? = null
@@ -28,6 +31,9 @@ class SMSService : Service(), TextToSpeech.OnInitListener {
private val notificationChannelId = "sms_service_channel"
private lateinit var notificationManager: NotificationManager
+ private lateinit var db: AppDatabase
+ lateinit var transactionDao: TransactionDao
+
companion object {
const val STOP_SERVICE = "STOP_SERVICE"
}
@@ -35,24 +41,25 @@ class SMSService : Service(), TextToSpeech.OnInitListener {
private val smsReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == Telephony.Sms.Intents.SMS_RECEIVED_ACTION) {
- val messages = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- Telephony.Sms.Intents.getMessagesFromIntent(intent)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ // For KitKat and above, use the bundled SMS API
+ val smsMessages = Telephony.Sms.Intents.getMessagesFromIntent(intent)
+ smsMessages?.forEach { smsMessage ->
+ val messageBody = smsMessage.messageBody
+ processMessage(messageBody)
+ }
} else {
+ // For older devices, parse SMS messages manually
val bundle = intent.extras
if (bundle != null) {
val pdus = bundle["pdus"] as Array<*>?
- pdus?.map { pdu ->
- SmsMessage.createFromPdu(pdu as ByteArray)
- }?.toTypedArray()
- } else {
- null
+ pdus?.forEach { pdu ->
+ val smsMessage = SmsMessage.createFromPdu(pdu as ByteArray)
+ val messageBody = smsMessage.messageBody
+ processMessage(messageBody)
+ }
}
}
-
- messages?.forEach { smsMessage ->
- val messageBody = smsMessage.messageBody
- processMessage(messageBody)
- }
}
}
}
@@ -68,15 +75,32 @@ class SMSService : Service(), TextToSpeech.OnInitListener {
override fun onCreate() {
super.onCreate()
tts = TextToSpeech(this, this)
- registerReceiver(smsReceiver, IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION))
+
+ this.db = (applicationContext as UPIAPP).database
+ transactionDao = db.transactionDao() // Initialize transactionDao
+
+ val smsIntentFilter = IntentFilter()
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
+ smsIntentFilter.addAction(Telephony.Sms.Intents.SMS_RECEIVED_ACTION)
+ } else {
+ smsIntentFilter.addAction("android.provider.Telephony.SMS_RECEIVED")
+ }
+ registerReceiver(smsReceiver, smsIntentFilter)
+
startMessageProcessing()
+
val filter = IntentFilter(STOP_SERVICE)
- registerReceiver(stopReceiver, filter)
+
+ if (Build.VERSION.SDK_INT >= 33 ){
+ registerReceiver(stopReceiver, filter, RECEIVER_NOT_EXPORTED)
+ } else {
+ registerReceiver(stopReceiver, filter)
+ }
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Start the service in the foreground (for Android 8.0 and above)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel() // Create channel before starting foreground
startForeground(notificationId, createNotification())
} else {
@@ -97,36 +121,41 @@ class SMSService : Service(), TextToSpeech.OnInitListener {
return
}
- if (message.contains("credited") && !message.contains("debited") && !message.contains("credited to")) {
- val regex = "Rs\\.?\\s*(\\d+(\\.\\d{2})?)".toRegex() // Match Rs or Rs.
- val matchResult = regex.find(message)
- matchResult?.let {
- val amount = it.groupValues[1]
- val announcementMessage = "Received Rupees $amount"
- Log.d("SMSService", "Queueing message: $announcementMessage")
- messageQueue.offer(announcementMessage)
- } ?: Log.d("SMSService", "No amount found in the message")
- } else if (message.contains("debited")) {
- val regex = "Rs\\.?\\s*(\\d+(\\.\\d{2})?)".toRegex() // Match Rs or Rs.
- val matchResult = regex.find(message)
- matchResult?.let {
- val amount = it.groupValues[1]
- val announcementMessage = "Sent Rupees $amount"
- Log.d("SMSService", "Queueing message: $announcementMessage")
- messageQueue.offer(announcementMessage)
- } ?: Log.d("SMSService", "No amount found in the message")
- } else if (message.contains("credited") && message.contains("credited to")) {
- val regex = "Rs\\.?\\s*(\\d+(\\.\\d{2})?)".toRegex() // Match Rs or Rs.
- val matchResult = regex.find(message)
- matchResult?.let {
- val amount = it.groupValues[1]
- val announcementMessage = "Received Rupees $amount"
+ val regex = "Rs\\.?\\s*(\\d+(\\.\\d{2})?)".toRegex()
+ val matchResult = regex.find(message)
+
+ var extractedName: String? = null
+ val nameRegex = "(?i)(?:from|From|FROM)\\s+(.*?)(?:\\.|thru|through)".toRegex()
+ val nameMatchResult = nameRegex.find(message)
+ extractedName = nameMatchResult?.groupValues?.getOrNull(1)?.trim()
+
+ matchResult?.let { result ->
+ val amount = result.groupValues[1].toDoubleOrNull()
+ if (amount != null) {
+ val type = when {
+ message.contains("credited") && !message.contains("debited") -> "Credit"
+ message.contains("debited") -> "Debit"
+ else -> {
+ Log.d("SMSService", "Message does not match criteria for announcement")
+ return
+ }
+ }
+
+ val date = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date())
+ val transaction = PayTransaction(amount = amount, type = type, date = date, name = extractedName ?: "") // Use empty string if name is null
+
+ scope.launch {
+ transactionDao.insert(transaction)
+ Log.d("SMSService", "Inserted transaction into database: $transaction")
+ }
+
+ val announcementMessage = "${if (type == "Credit") "Received" else "Sent"} Rupees $amount"
Log.d("SMSService", "Queueing message: $announcementMessage")
messageQueue.offer(announcementMessage)
- } ?: Log.d("SMSService", "No amount found in the message")
- } else {
- Log.d("SMSService", "Message does not match criteria for announcement")
- }
+ } else {
+ Log.d("SMSService", "Invalid amount format in the message")
+ }
+ } ?: Log.d("SMSService", "No amount found in the message")
}
private fun startMessageProcessing() {
@@ -164,10 +193,8 @@ class SMSService : Service(), TextToSpeech.OnInitListener {
.setAutoCancel(true)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- // For Android 8.0 and above, use the notification channel
notificationManager.notify(notificationId, notificationBuilder.build())
} else {
- // For older versions, show the notification directly
@Suppress("DEPRECATION")
notificationManager.notify(notificationId, notificationBuilder.build())
}
@@ -186,6 +213,8 @@ class SMSService : Service(), TextToSpeech.OnInitListener {
return notificationBuilder.build()
}
+
+
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // Check SDK version
val channel = NotificationChannel(
diff --git a/app/src/main/java/com/zeusinstitute/upiapp/TransactionAdapter.kt b/app/src/main/java/com/zeusinstitute/upiapp/TransactionAdapter.kt
new file mode 100644
index 0000000..c24699d
--- /dev/null
+++ b/app/src/main/java/com/zeusinstitute/upiapp/TransactionAdapter.kt
@@ -0,0 +1,49 @@
+package com.zeusinstitute.upiapp
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.ListAdapter
+import androidx.recyclerview.widget.RecyclerView
+import com.zeusinstitute.upiapp.PayTransaction
+
+class TransactionAdapter : ListAdapter(TransactionDiffCallback()) {
+
+ class TransactionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ val transactionStatusTextView: TextView = itemView.findViewById(R.id.transactionStatusTextView)
+ val transactionIcon: ImageView = itemView.findViewById(R.id.transactionIcon)
+ val transactionNameTextView: TextView = itemView.findViewById(R.id.transactionNameTextView)
+ val transactionAmountTextView: TextView = itemView.findViewById(R.id.transactionAmountTextView)
+ val transactionDateTextView: TextView = itemView.findViewById(R.id.transactionDateTextView)
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionViewHolder {
+ val itemView = LayoutInflater.from(parent.context).inflate(R.layout.transaction_item, parent, false)
+ return TransactionViewHolder(itemView)
+ }
+
+ override fun onBindViewHolder(holder: TransactionViewHolder, position: Int) {
+ val transaction = getItem(position)
+ holder.transactionIcon.setImageResource(
+ if (transaction.type == "Debit") R.drawable.ic_debit
+ else R.drawable.ic_credit
+ )
+ holder.transactionNameTextView.text = "${transaction.name}"
+ holder.transactionAmountTextView.text = "₹${transaction.amount}"
+ holder.transactionDateTextView.text = transaction.date
+ holder.transactionStatusTextView.text = if (transaction.type == "Debit") "Sent" else "Received"
+ }
+
+ class TransactionDiffCallback : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(oldItem: PayTransaction, newItem: PayTransaction): Boolean {
+ return oldItem.id == newItem.id
+ }
+
+ override fun areContentsTheSame(oldItem: PayTransaction, newItem: PayTransaction): Boolean {
+ return oldItem == newItem
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/zeusinstitute/upiapp/TransactionDao.kt b/app/src/main/java/com/zeusinstitute/upiapp/TransactionDao.kt
new file mode 100644
index 0000000..1a2bbf7
--- /dev/null
+++ b/app/src/main/java/com/zeusinstitute/upiapp/TransactionDao.kt
@@ -0,0 +1,24 @@
+package com.zeusinstitute.upiapp
+
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.Query
+import kotlinx.coroutines.flow.Flow
+
+@Dao
+interface TransactionDao {
+ @Insert
+ fun insert(transaction: PayTransaction)
+
+ @Query("SELECT * FROM PayTransaction ORDER BY date DESC")
+ fun getAll(): Flow>
+
+ @Query("DELETE FROM PayTransaction")
+ fun deleteAll()
+
+ @Query("SELECT * FROM PayTransaction")
+ fun getAllTransactions(): List
+
+ @Query("SELECT * FROM PayTransaction ORDER BY date DESC")
+ fun getAllTransactionsOrderedByDate(): Flow>
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/zeusinstitute/upiapp/UPIAPP.kt b/app/src/main/java/com/zeusinstitute/upiapp/UPIAPP.kt
new file mode 100644
index 0000000..76538b3
--- /dev/null
+++ b/app/src/main/java/com/zeusinstitute/upiapp/UPIAPP.kt
@@ -0,0 +1,22 @@
+package com.zeusinstitute.upiapp
+
+// ... other imports ...
+import android.app.Application
+import androidx.room.Room
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class UPIAPP : Application() {
+ val database: AppDatabase by lazy {
+ val MIGRATION_1_2 = object : Migration(1, 2) {
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("ALTER TABLE PayTransaction ADD COLUMN name TEXT NOT NULL")
+ }
+ }
+
+ Room.databaseBuilder(this, AppDatabase::class.java, "transactions")
+ .addMigrations(MIGRATION_1_2)
+ .fallbackToDestructiveMigration()
+ .build()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_credit.xml b/app/src/main/res/drawable/ic_credit.xml
new file mode 100644
index 0000000..d566a4c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_credit.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_debit.xml b/app/src/main/res/drawable/ic_debit.xml
new file mode 100644
index 0000000..9fa5e71
--- /dev/null
+++ b/app/src/main/res/drawable/ic_debit.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_bill_history.xml b/app/src/main/res/layout/fragment_bill_history.xml
new file mode 100644
index 0000000..5587fcb
--- /dev/null
+++ b/app/src/main/res/layout/fragment_bill_history.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/transaction_item.xml b/app/src/main/res/layout/transaction_item.xml
new file mode 100644
index 0000000..8cb3672
--- /dev/null
+++ b/app/src/main/res/layout/transaction_item.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml
index 88a2a9b..db4b462 100644
--- a/app/src/main/res/menu/menu_main.xml
+++ b/app/src/main/res/menu/menu_main.xml
@@ -14,6 +14,9 @@
+
diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml
index 8aa6ca2..4ae1f59 100644
--- a/app/src/main/res/navigation/nav_graph.xml
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -24,6 +24,9 @@
+
+
#FF000000
#FFFFFFFF
+ #4CAF50
+ #F44336
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index e68b281..7c65f37 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
- id 'com.android.application' version '8.4.1' apply false
- id 'com.android.library' version '8.4.1' apply false
+ id 'com.android.application' version '8.5.2' apply false
+ id 'com.android.library' version '8.5.2' apply false
id 'org.jetbrains.kotlin.android' version '1.8.20' apply false
+ id 'org.jetbrains.kotlin.kapt' version '2.0.10'
}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 31c4608..5a3fbf9 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Thu Jun 15 15:42:40 IST 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists