diff --git a/Source/GUI/Android/app/CMakeLists.txt b/Source/GUI/Android/app/CMakeLists.txt
index b350038c5..64f3a1b9c 100644
--- a/Source/GUI/Android/app/CMakeLists.txt
+++ b/Source/GUI/Android/app/CMakeLists.txt
@@ -10,6 +10,8 @@ set(BUILD_SHARED_LIBS ON CACHE BOOL "Force shared library build" FORCE)
set(LARGE_FILES OFF CACHE BOOL "Enable large files support" FORCE)
set(BUILD_ZENLIB ON CACHE BOOL "Build bundled ZenLib" FORCE)
+find_package(curl REQUIRED CONFIG)
+
add_subdirectory(../../../../../MediaInfoLib/Project/CMake ${CMAKE_CURRENT_BINARY_DIR}/MediaInfoLib)
target_link_options(mediainfo
diff --git a/Source/GUI/Android/app/build.gradle b/Source/GUI/Android/app/build.gradle
index 54a110d4f..b84f3eeb2 100644
--- a/Source/GUI/Android/app/build.gradle
+++ b/Source/GUI/Android/app/build.gradle
@@ -14,7 +14,7 @@ android {
defaultConfig {
applicationId "net.mediaarea.mediainfo"
multiDexEnabled = true
- minSdkVersion 21
+ minSdkVersion 23
versionCode 59
versionName "26.05"
targetSdkVersion 37
@@ -32,20 +32,18 @@ android {
"-DMEDIAINFO_DUPLICATE=OFF",
"-DMEDIAINFO_DVDIF_ANALYZE=OFF",
"-DMEDIAINFO_EVENTS=OFF",
+ "-DMEDIAINFO_FILE=OFF",
"-DMEDIAINFO_FILTER=OFF",
"-DMEDIAINFO_FIXITY=OFF",
"-DMEDIAINFO_GRAPH=OFF",
"-DMEDIAINFO_IBI=OFF",
- "-DMEDIAINFO_LIBCURL=OFF",
"-DMEDIAINFO_LIBMMS=OFF",
"-DMEDIAINFO_MACROBLOCKS=OFF",
"-DMEDIAINFO_MD5=OFF",
"-DMEDIAINFO_NEXTPACKET=OFF",
- "-DMEDIAINFO_READER=OFF",
"-DMEDIAINFO_READTHREAD=OFF",
"-DMEDIAINFO_REFERENCES=OFF",
"-DMEDIAINFO_SHA1=OFF",
- "-DMEDIAINFO_SHA2=OFF",
"-DMEDIAINFO_TRACE=OFF",
"-DMEDIAINFO_TRACE_FFV1CONTENT=OFF"
}
@@ -77,6 +75,9 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+ buildFeatures {
+ prefab = true
+ }
externalNativeBuild {
cmake {
path "CMakeLists.txt"
@@ -202,9 +203,9 @@ tasks.register('copyLocales', DefaultTask) {
preBuild.dependsOn copyLocales
dependencies {
- implementation 'com.google.android.material:material:1.13.0' // can only upgrade when minSdkVersion >= 23
+ implementation 'com.google.android.material:material:1.14.0'
implementation 'androidx.appcompat:appcompat:1.7.1'
- implementation "androidx.core:core-ktx:1.17.0" // can only upgrade when minSdkVersion >= 23
+ implementation "androidx.core:core-ktx:1.18.0"
implementation 'androidx.documentfile:documentfile:1.1.0'
implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
@@ -213,19 +214,19 @@ dependencies {
androidTestImplementation 'androidx.test:runner:1.7.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0'
// Android Room
- // can only upgrade when minSdkVersion >= 23
- implementation 'androidx.room:room-runtime:2.7.2'
- implementation 'androidx.room:room-ktx:2.7.2'
- ksp 'androidx.room:room-compiler:2.7.2'
+ implementation 'androidx.room:room-runtime:2.8.4'
+ implementation 'androidx.room:room-ktx:2.8.4'
+ ksp 'androidx.room:room-compiler:2.8.4'
// Android Lifecycle
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
ksp "androidx.lifecycle:lifecycle-common-java8:2.10.0"
// Google Billing
- // can only upgrade when minSdkVersion >= 23
- implementation "com.android.billingclient:billing:8.0.0"
- implementation "com.android.billingclient:billing-ktx:8.0.0"
+ implementation "com.android.billingclient:billing:9.0.0"
+ implementation "com.android.billingclient:billing-ktx:9.0.0"
// KotlinX Coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0"
// Locales manager
implementation 'com.github.YarikSOffice:lingver:1.3.0'
+ // Curl static build from https://github.com/vvb2060/curl-android
+ implementation "io.github.vvb2060.ndk:curl:8.18.0"
}
diff --git a/Source/GUI/Android/app/src/main/AndroidManifest.xml b/Source/GUI/Android/app/src/main/AndroidManifest.xml
index 1f3ed1ac9..59923717f 100644
--- a/Source/GUI/Android/app/src/main/AndroidManifest.xml
+++ b/Source/GUI/Android/app/src/main/AndroidManifest.xml
@@ -11,6 +11,7 @@
+
+
diff --git a/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/Core.kt b/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/Core.kt
index 9291f5c58..2da2109a7 100644
--- a/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/Core.kt
+++ b/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/Core.kt
@@ -6,6 +6,8 @@
package net.mediaarea.mediainfo
+import android.net.Uri
+
object Core {
data class ReportView(val name: String, val desc: String, val mime: String, val exportable: Boolean) {
override fun toString(): String {
@@ -47,6 +49,21 @@ object Core {
return report.toByteArray()
}
+ @Synchronized
+ fun createReport(networkUri: Uri): ByteArray {
+ mi.Option("Language", "")
+ mi.Option("Inform", "MIXML")
+ mi.Option("Input_Compressed", "")
+ mi.Option("Inform_Compress", "zlib+base64")
+ mi.Option("File_FileName") // Reset filename so that MediaInfoLib does not use previous filename
+
+ mi.Open(networkUri.toString())
+ val report: String = mi.Inform()
+ mi.Close()
+
+ return report.toByteArray()
+ }
+
@Synchronized
fun convertReport(report: ByteArray, format: String, export: Boolean = false) : String {
mi.Option("Inform", format)
diff --git a/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/MediaInfo.kt b/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/MediaInfo.kt
index 839da2165..b2d5c0a04 100644
--- a/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/MediaInfo.kt
+++ b/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/MediaInfo.kt
@@ -43,7 +43,7 @@ class MediaInfo {
external fun Init(): Long
external fun Destroy(): Int
private external fun OpenFd(fd: Int, name: String): Int
- private external fun Open(name:String ): Int
+ external fun Open(name:String): Int
fun Open(fd: Int, name: String): Int {
return OpenFd(fd, name)
}
diff --git a/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/ReportListActivity.kt b/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/ReportListActivity.kt
index d1d230391..8c9b5fb26 100644
--- a/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/ReportListActivity.kt
+++ b/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/ReportListActivity.kt
@@ -6,7 +6,7 @@
package net.mediaarea.mediainfo
-import kotlin.jvm.*
+import kotlin.math.abs
import kotlinx.coroutines.launch
import androidx.activity.result.contract.ActivityResultContracts
@@ -27,9 +27,11 @@ import androidx.lifecycle.repeatOnLifecycle
import androidx.lifecycle.ViewModelProvider
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.google.android.material.listitem.ListItemViewHolder
import android.os.Build
import android.os.Bundle
@@ -43,12 +45,16 @@ import android.content.pm.PackageManager
import android.content.res.Configuration
import android.content.res.Resources
import android.provider.Settings
-import android.view.*
+import android.util.Patterns
+import android.view.Menu
+import android.view.View
+import android.view.ViewConfiguration
+import android.view.ViewGroup
import com.yariksoffice.lingver.Lingver
import kotlinx.coroutines.flow.collectLatest
import java.io.BufferedReader
-import java.util.*
+import java.util.Locale
import net.mediaarea.mediainfo.databinding.ActivityReportListBinding
import net.mediaarea.mediainfo.databinding.ClearButtonBinding
@@ -169,14 +175,12 @@ class ReportListActivity : AppCompatActivity(), ReportActivityListener {
private fun handleUri(uri: Uri, isMultiple: Boolean = false) {
when (uri.scheme) {
"file" -> {
- if (Build.VERSION.SDK_INT >= 23) {
- if (checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
- pendingFileUris.add(uri)
- ActivityCompat.requestPermissions(this@ReportListActivity,
- arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE),
- READ_EXTERNAL_STORAGE_PERMISSION_REQUEST)
- return
- }
+ if (checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
+ pendingFileUris.add(uri)
+ ActivityCompat.requestPermissions(this@ReportListActivity,
+ arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE),
+ READ_EXTERNAL_STORAGE_PERMISSION_REQUEST)
+ return
}
}
"content" -> {
@@ -234,7 +238,15 @@ class ReportListActivity : AppCompatActivity(), ReportActivityListener {
}
Intent.ACTION_SEND -> {
val uri =
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ if (intent.type == "text/plain") {
+ intent.getStringExtra(Intent.EXTRA_TEXT)?.let { text ->
+ val matcher = Patterns.WEB_URL.matcher(text)
+ if (matcher.find())
+ matcher.group().toUri()
+ else
+ null
+ }
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
} else {
@Suppress("DEPRECATION")
@@ -708,6 +720,25 @@ class ReportListActivity : AppCompatActivity(), ReportActivityListener {
private fun setupRecyclerView(recyclerView: RecyclerView) {
recyclerView.adapter = ItemRecyclerViewAdapter()
+ val layoutManager = recyclerView.layoutManager as? LinearLayoutManager
+ val extFab = activityReportListBinding.addButton
+ val scaledTouchSlop = ViewConfiguration.get(recyclerView.context).scaledTouchSlop
+
+ recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+ override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+ super.onScrolled(recyclerView, dx, dy)
+
+ if (abs(dy) <= scaledTouchSlop) {
+ if (!extFab.isExtended && layoutManager?.findFirstCompletelyVisibleItemPosition() == 0)
+ extFab.extend()
+ return
+ }
+ if (dy > 0 && extFab.isExtended)
+ extFab.shrink()
+ else if (dy < 0 && !extFab.isExtended)
+ extFab.extend()
+ }
+ })
}
sealed class ReportListItem {
@@ -794,6 +825,7 @@ class ReportListActivity : AppCompatActivity(), ReportActivityListener {
is ReportListItem.ReportData -> {
if (holder is ListViewHolder) {
val report: Report = item.report
+ holder.bind(position, currentList.size - 1) // Last is button
holder.name.text = report.filename
holder.id = report.id
with(holder.itemView) {
@@ -805,6 +837,7 @@ class ReportListActivity : AppCompatActivity(), ReportActivityListener {
}
is ReportListItem.ClearButton -> {
if (holder is ButtonViewHolder) {
+ holder.bind(0, 1)
with(holder.itemView) {
setOnClickListener {
reportModel.deleteAllReports()
@@ -828,7 +861,7 @@ class ReportListActivity : AppCompatActivity(), ReportActivityListener {
}
}
- inner class ListViewHolder(binding: ReportListContentBinding) : RecyclerView.ViewHolder(binding.root) {
+ inner class ListViewHolder(binding: ReportListContentBinding) : ListItemViewHolder(binding.root) {
val name: TextView = binding.nameText
var id: Int = -1
@@ -840,7 +873,7 @@ class ReportListActivity : AppCompatActivity(), ReportActivityListener {
}
}
- inner class ButtonViewHolder(val binding: ClearButtonBinding) : RecyclerView.ViewHolder(binding.root)
+ inner class ButtonViewHolder(val binding: ClearButtonBinding) : ListItemViewHolder(binding.root)
}
companion object {
diff --git a/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/ReportViewModel.kt b/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/ReportViewModel.kt
index d71373837..f90d56447 100644
--- a/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/ReportViewModel.kt
+++ b/Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/ReportViewModel.kt
@@ -58,6 +58,7 @@ class ReportViewModel(private val dataSource: ReportDao) : ViewModel() {
for (uri in uris) {
var fd: ParcelFileDescriptor? = null
var displayName = ""
+ var isUrl = false
when (uri.scheme) {
"content" -> {
@@ -94,17 +95,23 @@ class ReportViewModel(private val dataSource: ReportDao) : ViewModel() {
displayName = uri.lastPathSegment.orEmpty()
}
+
+ "http", "https", "ftp", "sftp" -> {
+ isUrl = true
+ displayName = uri.lastPathSegment.orEmpty()
+ }
}
- if (fd == null) {
+ if (fd == null && !isUrl) {
continue
}
- fd.use {
- val report: ByteArray = Core.createReport(it.detachFd(), displayName)
- lastInsertedId =
- insertReport(Report(0, displayName, report, Core.version)).toInt()
- }
+ val report: ByteArray =
+ fd?.use { Core.createReport(it.detachFd(), displayName) }
+ ?: Core.createReport(uri)
+
+ lastInsertedId =
+ insertReport(Report(0, displayName, report, Core.version)).toInt()
}
// Don't go to report view when opening multiple files
diff --git a/Source/GUI/Android/app/src/main/res/color/listitemcardview_selector.xml b/Source/GUI/Android/app/src/main/res/color/listitemcardview_selector.xml
new file mode 100644
index 000000000..be2d9154e
--- /dev/null
+++ b/Source/GUI/Android/app/src/main/res/color/listitemcardview_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/GUI/Android/app/src/main/res/layout/activity_about.xml b/Source/GUI/Android/app/src/main/res/layout/activity_about.xml
index 343caf8e2..077a7323d 100644
--- a/Source/GUI/Android/app/src/main/res/layout/activity_about.xml
+++ b/Source/GUI/Android/app/src/main/res/layout/activity_about.xml
@@ -12,15 +12,13 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:fitsSystemWindows="true"
tools:context=".AboutActivity">
+ app:liftOnScroll="true">
-
-
+
\ No newline at end of file
diff --git a/Source/GUI/Android/app/src/main/res/layout/activity_report_list.xml b/Source/GUI/Android/app/src/main/res/layout/activity_report_list.xml
index 6f7ca3da8..380388d3f 100644
--- a/Source/GUI/Android/app/src/main/res/layout/activity_report_list.xml
+++ b/Source/GUI/Android/app/src/main/res/layout/activity_report_list.xml
@@ -28,6 +28,7 @@
-
+ android:text="@string/open_title"
+ app:icon="@drawable/ic_action_add" />
\ No newline at end of file
diff --git a/Source/GUI/Android/app/src/main/res/layout/activity_settings.xml b/Source/GUI/Android/app/src/main/res/layout/activity_settings.xml
index b6280e095..2d35ea808 100644
--- a/Source/GUI/Android/app/src/main/res/layout/activity_settings.xml
+++ b/Source/GUI/Android/app/src/main/res/layout/activity_settings.xml
@@ -15,10 +15,10 @@
tools:context=".SettingsActivity">
+ android:id="@+id/app_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:liftOnScroll="true">
+ android:layout_height="wrap_content"
+ app:liftOnScroll="true">
-
-
+
\ No newline at end of file
diff --git a/Source/GUI/Android/app/src/main/res/layout/clear_button.xml b/Source/GUI/Android/app/src/main/res/layout/clear_button.xml
index 4b1f83389..3bd3b5503 100644
--- a/Source/GUI/Android/app/src/main/res/layout/clear_button.xml
+++ b/Source/GUI/Android/app/src/main/res/layout/clear_button.xml
@@ -1,10 +1,31 @@
-
\ No newline at end of file
+ android:layout_marginHorizontal="8dp"
+ android:layout_marginVertical="8dp">
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/GUI/Android/app/src/main/res/layout/report_list_content.xml b/Source/GUI/Android/app/src/main/res/layout/report_list_content.xml
index fde8b3b4a..7c8bcd834 100644
--- a/Source/GUI/Android/app/src/main/res/layout/report_list_content.xml
+++ b/Source/GUI/Android/app/src/main/res/layout/report_list_content.xml
@@ -6,39 +6,59 @@
be found in the License.html file in the root of the source tree.
-->
-
-
-
-
-
+
+
-
-
\ No newline at end of file
+ app:contentPaddingTop="0dp"
+ app:contentPaddingBottom="0dp"
+ app:contentPaddingLeft="0dp"
+ app:contentPaddingRight="0dp"
+ app:cardBackgroundColor="@color/listitemcardview_selector">
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/GUI/Android/app/src/main/res/values/styles.xml b/Source/GUI/Android/app/src/main/res/values/styles.xml
index 0b1ab2211..405118a5a 100644
--- a/Source/GUI/Android/app/src/main/res/values/styles.xml
+++ b/Source/GUI/Android/app/src/main/res/values/styles.xml
@@ -8,7 +8,7 @@
-
-
-
diff --git a/Source/GUI/Android/build.gradle b/Source/GUI/Android/build.gradle
index 57108c52c..4151b6876 100644
--- a/Source/GUI/Android/build.gradle
+++ b/Source/GUI/Android/build.gradle
@@ -6,8 +6,8 @@ buildscript {
mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:9.2.0'
- classpath 'com.android.tools.build:gradle-settings-api:9.2.0'
+ classpath 'com.android.tools.build:gradle:9.2.1'
+ classpath 'com.android.tools.build:gradle-settings-api:9.2.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files