diff --git a/.gitignore b/.gitignore
index 7bb94c84..bc6ff762 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,5 +13,8 @@
app/build
app/build/generated/not_namespaced_r_class_sources/debug/processDebugResources/r/androidx/asynclayoutinflater/R.java
app/nonFree
+app/nonFreeMobile
+app/standardMobile
+app/standardTv
app/standard
.idea/kotlinc.xml
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index f38c8fbb..46791710 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -15,10 +15,14 @@
UI improvements for bigger tablets and Chromebooks.
+App should now be resizable if Samsung DeX is enabled.
+Bugfixes and general improvements.
+ +Added querying for System Renawability Message (SRM) properties for Widevine.
+Listing secure decoders on Android 5.0-6.0 should now be more reliable.
+Added a workaround for Oppo R9 not listing a generic raw audio decoder.
+(Android TV) Significant APK size reduction.
+Reported max resolution should be now more accurate for some codecs.
+Codec Info will now detect and inform users about known issues with some codecs. If you know about an issue that's not being displayed, please send a feedback email about it!
Added a notification for the user if getting a codec list is impossible due to an Android platform bug.
diff --git a/app/src/main/java/com/parseus/codecinfo/data/codecinfo/CodecUtils.kt b/app/src/main/java/com/parseus/codecinfo/data/codecinfo/CodecUtils.kt index 58406c79..e959c111 100644 --- a/app/src/main/java/com/parseus/codecinfo/data/codecinfo/CodecUtils.kt +++ b/app/src/main/java/com/parseus/codecinfo/data/codecinfo/CodecUtils.kt @@ -2,10 +2,12 @@ package com.parseus.codecinfo.data.codecinfo import android.annotation.SuppressLint import android.content.Context +import android.media.MediaCodec import android.media.MediaCodecInfo import android.media.MediaCodecInfo.CodecCapabilities.* import android.media.MediaCodecList import android.media.MediaFormat +import android.os.Build import android.os.Build.VERSION.SDK_INT import android.util.Range import androidx.annotation.RequiresApi @@ -16,10 +18,7 @@ import com.parseus.codecinfo.data.DetailsProperty import com.parseus.codecinfo.data.codecinfo.colorformats.* import com.parseus.codecinfo.data.codecinfo.profilelevels.* import com.parseus.codecinfo.data.codecinfo.profilelevels.VP9Levels.* -import com.parseus.codecinfo.utils.isAudioCodec -import com.parseus.codecinfo.utils.toBytesPerSecond -import com.parseus.codecinfo.utils.toHexHstring -import com.parseus.codecinfo.utils.toKiloHertz +import com.parseus.codecinfo.utils.* import java.util.* import kotlin.collections.ArrayList @@ -39,6 +38,9 @@ private const val DIVX6_1080P_MAX_FRAME_RATE = 30 private val DIVX4_MAX_RESOLUTION = intArrayOf(720, 576) private val DIVX6_MAX_RESOLUTION = intArrayOf(1920, 1080) +private const val GOOGLE_RAW_DECODER = "OMX.google.raw.decoder" +private const val MEDIATEK_RAW_DECODER = "OMX.MTK.AUDIO.DECODER.RAW" + private val platformSupportedTypes = arrayOf( "audio/3gpp", "audio/amr-mb", @@ -102,11 +104,38 @@ fun getSimpleCodecInfoList(context: Context, isAudio: Boolean): MutableList MediaCodecList.getCodecInfoAt(i) }
+ try {
+ @Suppress("DEPRECATION")
+ Array(MediaCodecList.getCodecCount()) { i -> MediaCodecList.getCodecInfoAt(i) }
+ } catch (e: Exception) {
+ return mutableListOf()
+ }
}
}
+ if (SDK_INT in 21..23 && mediaCodecInfos.find { it.name.endsWith("secure") } == null) {
+ // Some devices don't list secure decoders on API 21 with a newer way of querying codecs,
+ // but potentially could also happen on API levels 22 and 23.
+ // In that case try the old way.
+ try {
+ @Suppress("DEPRECATION")
+ val oldCodecInfos = Array(MediaCodecList.getCodecCount())
+ { i -> MediaCodecList.getCodecInfoAt(i) }.filter { it.name.endsWith("secure") }
+ mediaCodecInfos += oldCodecInfos
+ } catch (e: Exception) {}
+ }
+
+ if (SDK_INT in 22..25 && Build.DEVICE == "R9"
+ && mediaCodecInfos.find { it.name == GOOGLE_RAW_DECODER } == null
+ && mediaCodecInfos.find { it.name == MEDIATEK_RAW_DECODER } != null) {
+ // Oppo R9 does not list a generic raw audio decoder, yet it can be instantiated by name.
+ try {
+ val rawMediaCodec = MediaCodec.createByCodecName(GOOGLE_RAW_DECODER)
+ //noinspection NewApi
+ mediaCodecInfos += rawMediaCodec.codecInfo
+ } catch (e: Exception) {}
+ }
+
val showAliases = prefs.getBoolean("show_aliases", false)
val filteringOption = prefs.getString("filter_type", "2")!!.toInt()
var codecSimpleInfoList = ArrayList()
@@ -447,12 +476,12 @@ private fun adjustMaxInputChannelCount(codecId: String, codecName: String, maxCh
}
}
- if (SDK_INT < 28) {
+ if (CAN_USE_REFLECTION_FOR_MCAPABILITIESINFO) {
/*
mCapabilitiesInfo, a private MediaFormat instance hidden in MediaCodecInfo,
can actually provide max input channel count (as well as other useful info).
- Unfortunately, with P restricting non-API usage via reflection, I can only hope
- that everything will work fine on newer versions.
+ Android 9.0 put it on a dark greylist, though, so it can't be easily accessed anymore
+ (although it is bypassed on a non-store mobile flavor). Newer versions are SOL here.
*/
try {
val capabilitiesInfo = capabilities::class.java.getDeclaredField("mCapabilitiesInfo")
@@ -462,8 +491,7 @@ private fun adjustMaxInputChannelCount(codecId: String, codecName: String, maxCh
if (mediaFormat.containsKey("max-channel-count")) {
return mediaFormat.getString("max-channel-count")!!.toInt()
}
- } catch (e: Exception) {
- }
+ } catch (e: Exception) {}
}
if (codecId.endsWith("flac") || codecId.endsWith("alac")) {
@@ -582,7 +610,7 @@ private fun addColorFormats(capabilities: MediaCodecInfo.CodecCapabilities, code
private fun getFormattedColorProfileString(context: Context, colorFormat: String, colorFormatInt: Int): String {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
- return when (prefs.getString("known_values_color_profiles", "0")!!.toInt()) {
+ return when (prefs.getString("known_values_color_profiles", "1")!!.toInt()) {
0 -> colorFormat
1 -> "$colorFormat (${colorFormatInt.toHexHstring()})"
else -> "$colorFormat ($colorFormatInt)"
@@ -592,7 +620,7 @@ private fun getFormattedColorProfileString(context: Context, colorFormat: String
@RequiresApi(21)
private fun getMaxResolution(codecId: String, videoCapabilities: MediaCodecInfo.VideoCapabilities): IntArray {
val maxWidth = videoCapabilities.supportedWidths.upper
- val maxHeight = videoCapabilities.getSupportedHeightsFor(maxWidth).upper
+ val maxHeight = videoCapabilities.supportedHeights.upper
val defaultResolution = intArrayOf(maxWidth, maxHeight)
return if (!areCapabilitiesUnknown(videoCapabilities)) {
@@ -803,7 +831,7 @@ private fun getProfileLevels(context: Context, codecId: String, codecName: Strin
private fun getFormattedProfileLevelString(context: Context, profile: String?, profileInt: Int,
level: String?, levelInt: Int): String {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
- val option = prefs.getString("known_values_profile_levels", "0")!!.toInt()
+ val option = prefs.getString("known_values_profile_levels", "1")!!.toInt()
val unknownString = context.getString(R.string.unknown)
val profileString = when (option) {
@@ -872,7 +900,7 @@ private fun getMaxVP9ProfileLevel(capabilities: MediaCodecInfo.CodecCapabilities
}
private fun isVendor(codecInfo: MediaCodecInfo): Boolean {
- val codecName = codecInfo.name.toLowerCase(Locale.ENGLISH)
+ val codecName = codecInfo.name.lowercase(Locale.ENGLISH)
return (!codecName.startsWith("omx.google.")
&& !codecName.startsWith("c2.android.")
&& !codecName.startsWith("c2.google.")
@@ -885,7 +913,7 @@ private fun isSoftwareOnly(codecInfo: MediaCodecInfo): Boolean {
return codecInfo.isSoftwareOnly
}
- val codecName = codecInfo.name.toLowerCase(Locale.ENGLISH)
+ val codecName = codecInfo.name.lowercase(Locale.ENGLISH)
// Broadcom codecs which specifically mention HW acceleration in their names
if (codecName.contains("omx.brcm.video", true) && codecName.contains("hw", true)) {
diff --git a/app/src/main/java/com/parseus/codecinfo/data/drm/DrmVendor.kt b/app/src/main/java/com/parseus/codecinfo/data/drm/DrmVendor.kt
index 0060b149..155e927c 100644
--- a/app/src/main/java/com/parseus/codecinfo/data/drm/DrmVendor.kt
+++ b/app/src/main/java/com/parseus/codecinfo/data/drm/DrmVendor.kt
@@ -70,7 +70,9 @@ enum class DrmVendor(val uuid: UUID,
R.string.drm_property_hdcp_level to "hdcpLevel",
R.string.drm_property_max_hdcp_level to "maxHdcpLevel",
R.string.drm_property_open_sessions to "numberOfOpenSessions",
- R.string.drm_property_max_sessions to "maxNumberOfSessions"
+ R.string.drm_property_max_sessions to "maxNumberOfSessions",
+ R.string.drm_property_current_srm_version to "CurrentSRMVersion",
+ R.string.drm_property_srm_update_support to "SRMUpdateSupport"
)
val WIDEVINE_BYTE_ARRAY_PROPERTIES = mapOf(
diff --git a/app/src/main/java/com/parseus/codecinfo/utils/Extensions.kt b/app/src/main/java/com/parseus/codecinfo/utils/Extensions.kt
index 92e292f8..1fc72268 100644
--- a/app/src/main/java/com/parseus/codecinfo/utils/Extensions.kt
+++ b/app/src/main/java/com/parseus/codecinfo/utils/Extensions.kt
@@ -7,8 +7,8 @@ import android.media.MediaCodecInfo
import java.util.*
fun Context.isTv(): Boolean {
- val uiModeManager = getSystemService(Context.UI_MODE_SERVICE) as UiModeManager
- return uiModeManager.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION
+ val uiModeManager = getSystemService(Context.UI_MODE_SERVICE) as? UiModeManager
+ return uiModeManager?.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION
}
fun Int.toKiloHertz(): Float {
@@ -26,7 +26,7 @@ fun Int.toBytesPerSecond(): String {
}
fun Int.toHexHstring(): String {
- return "0x${this.toString(16).toUpperCase(Locale.getDefault())}"
+ return "0x${this.toString(16).uppercase(Locale.getDefault())}"
}
fun ByteArray.toHexString(): String {
diff --git a/app/src/main/res/raw/known_problems_list.json b/app/src/main/res/raw/known_problems_list.json
index 0e90cad0..b47bf45a 100644
--- a/app/src/main/res/raw/known_problems_list.json
+++ b/app/src/main/res/raw/known_problems_list.json
@@ -447,5 +447,25 @@
"https://github.com/google/ExoPlayer/issues/4519",
"https://github.com/google/ExoPlayer/pull/5216"
]
+ },
+ {
+ "id": 18,
+ "codec_name": "OMX.google.raw.decoder",
+ "description": "This device does not list a generic raw audio decoder, yet it can be instantiated by name.",
+ "versions": [
+ {
+ "op": "<",
+ "value": 26
+ }
+ ],
+ "devices": [
+ {
+ "op": "equals",
+ "value": "R9"
+ }
+ ],
+ "urls": [
+ "https://github.com/google/ExoPlayer/issues/5782"
+ ]
}
]
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index b7dfca65..92f6cbe0 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -3,6 +3,6 @@
28dp
20dp
- 16dp
+ 16dp
\ 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 41dd5385..f9137ea5 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -2,30 +2,14 @@
&app_name;
-
- com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior
Version %1$s\n\u00A9 2018–2021 KN-Soft
- Close details
-
- Share
- Choose info to share
- Codec list
- Selected codec details
- All codecs and DRMs with details
-
Settings
About &app_name;…
Version %s
\u00A9 2018-2021 KN-Soft
https://github.com/Parseus/codecinfo
- parseus.dev@gmail.com
- Feedback
- Send feedback via…
- No apps can perform this action.
- No apps can perform this action. Email address was copied to the clipboard.
-
Search
Search codec/DRM info
Codec/DRM info
@@ -120,6 +104,8 @@
Application ID
Origin
Service certificate
+ Current System Renewability Message (SRM) version
+ System Renewability Message (SRM) update supported
ClearKey (DASH-IF)
ClearKey (Common PSSH box format)
@@ -134,19 +120,6 @@
HDCP 2.3 Type 1
No digital output (implicitly secure)
- Light
- Dark
- Set by Battery Saver
- System default
-
- Tap here to see more info…
-
- item_details
-
- %1$s codec %2$d - %3$s: %4$s for %5$s
- %1$s codec %2$d - %3$s: %4$s for %5$s. Known issue detected!
- DRM %1$d: %2$s
-
Known issue(s) detected:
Description:
Sources:
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index df72cb61..3d04c721 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -1,20 +1,11 @@
-
+
+
-
-
-
-
+
+
\ No newline at end of file
diff --git a/app/src/mobile/AndroidManifest.xml b/app/src/mobile/AndroidManifest.xml
index 8abbaf7c..5df99548 100644
--- a/app/src/mobile/AndroidManifest.xml
+++ b/app/src/mobile/AndroidManifest.xml
@@ -1,10 +1,15 @@
-
+
@@ -18,11 +23,24 @@
+
+
+
+ android:parentActivityName=".ui.MainActivity">
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/mobile/java/com/parseus/codecinfo/ui/ItemDetailsHeaderView.kt b/app/src/mobile/java/com/parseus/codecinfo/ui/ItemDetailsHeaderView.kt
new file mode 100644
index 00000000..92f0c567
--- /dev/null
+++ b/app/src/mobile/java/com/parseus/codecinfo/ui/ItemDetailsHeaderView.kt
@@ -0,0 +1,42 @@
+package com.parseus.codecinfo.ui
+
+import android.animation.AnimatorInflater
+import android.content.Context
+import android.util.AttributeSet
+import androidx.annotation.RequiresApi
+import com.google.android.material.textview.MaterialTextView
+import com.parseus.codecinfo.R
+import com.parseus.codecinfo.utils.getAttributeColor
+
+@RequiresApi(21)
+class ItemDetailsHeaderView : MaterialTextView {
+
+ var isHeaderLifted: Boolean = false
+ set(value) {
+ field = value
+ refreshDrawableState()
+ }
+
+ constructor(context: Context): super(context)
+ constructor(context: Context, attrs: AttributeSet?): super(context, attrs)
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int): super(context, attrs, defStyleAttr)
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int): super(context, attrs, defStyleAttr, defStyleRes)
+
+ init {
+ setBackgroundColor(context.getAttributeColor(com.google.android.material.R.attr.colorSurface))
+ stateListAnimator = AnimatorInflater.loadStateListAnimator(context, R.animator.item_details_header_state_list_animator)
+ }
+
+ override fun onCreateDrawableState(extraSpace: Int): IntArray {
+ return super.onCreateDrawableState(extraSpace + 1).also {
+ if (isHeaderLifted) {
+ mergeDrawableStates(it, STATE_LIFTED)
+ }
+ }
+ }
+
+ companion object {
+ private val STATE_LIFTED = intArrayOf(R.attr.state_header_lifted)
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/mobile/java/com/parseus/codecinfo/ui/MainActivity.kt b/app/src/mobile/java/com/parseus/codecinfo/ui/MainActivity.kt
index 2c168734..53c8e8d0 100644
--- a/app/src/mobile/java/com/parseus/codecinfo/ui/MainActivity.kt
+++ b/app/src/mobile/java/com/parseus/codecinfo/ui/MainActivity.kt
@@ -56,6 +56,8 @@ class MainActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
val searchListeners = mutableListOf()
override fun onCreate(savedInstanceState: Bundle?) {
+ disableApiBlacklistOnPie()
+
if (Build.VERSION.SDK_INT >= 21) {
val reenter = MaterialSharedAxis(MaterialSharedAxis.Z, false).apply {
excludeTarget(android.R.id.statusBarBackground, true)
@@ -72,7 +74,7 @@ class MainActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
}
}
- setTheme(R.style.AppTheme)
+ setTheme(R.style.Theme_CodecInfo)
super.onCreate(savedInstanceState)
@@ -287,8 +289,8 @@ class MainActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
}
}
val isCodecShared = InfoType.currentInfoType != InfoType.DRM
- if ((isCodecShared && (codecId == null || codecName == null))
- || (!isCodecShared && (drmName == null || drmUuid == null))) {
+ if (option > 1 && ((isCodecShared && (codecId == null || codecName == null))
+ || (!isCodecShared && (drmName == null || drmUuid == null)))) {
return
}
@@ -298,6 +300,7 @@ class MainActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
2 -> if (isCodecShared) {
getSelectedCodecInfoString(this, codecId!!, codecName!!)
} else {
+ //noinspection NewApi
getSelectedDrmInfoString(this, drmName!!, drmUuid!!)
}
else -> ""
diff --git a/app/src/mobile/java/com/parseus/codecinfo/ui/adapters/CodecAdapter.kt b/app/src/mobile/java/com/parseus/codecinfo/ui/adapters/CodecAdapter.kt
index 73736117..d0d426f0 100644
--- a/app/src/mobile/java/com/parseus/codecinfo/ui/adapters/CodecAdapter.kt
+++ b/app/src/mobile/java/com/parseus/codecinfo/ui/adapters/CodecAdapter.kt
@@ -1,8 +1,10 @@
package com.parseus.codecinfo.ui.adapters
+import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.appcompat.widget.SearchView
import androidx.core.os.bundleOf
import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
@@ -137,7 +139,9 @@ class CodecAdapter : RecyclerView.Adapter() {
ViewCompat.setTransitionName(layout, "$codecId/$codecName")
layout.setOnClickListener {
- val activity = (layout.context as MainActivity)
+ val context = layout.context
+ val activity = if (context is MainActivity) context
+ else (layout.context as ContextThemeWrapper).baseContext as MainActivity
// Do not create the same fragment again.
activity.supportFragmentManager
@@ -157,6 +161,11 @@ class CodecAdapter : RecyclerView.Adapter() {
fragment.sharedElementEnterTransition = buildContainerTransform(layout, true)
fragment.sharedElementReturnTransition = buildContainerTransform(layout, false)
}
+ fragment.searchListenerDestroyedListener = object : SearchListenerDestroyedListener {
+ override fun onSearchListenerDestroyed(queryTextListener: SearchView.OnQueryTextListener) {
+ activity.searchListeners.remove(queryTextListener)
+ }
+ }
}
val existingFragment = activity.searchListeners.find { it is DetailsFragment }
diff --git a/app/src/mobile/java/com/parseus/codecinfo/ui/adapters/DrmAdapter.kt b/app/src/mobile/java/com/parseus/codecinfo/ui/adapters/DrmAdapter.kt
index fa1a0a54..fa374bea 100644
--- a/app/src/mobile/java/com/parseus/codecinfo/ui/adapters/DrmAdapter.kt
+++ b/app/src/mobile/java/com/parseus/codecinfo/ui/adapters/DrmAdapter.kt
@@ -1,8 +1,10 @@
package com.parseus.codecinfo.ui.adapters
+import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.appcompat.widget.SearchView
import androidx.core.os.bundleOf
import androidx.core.view.ViewCompat
import androidx.fragment.app.commit
@@ -96,7 +98,9 @@ class DrmAdapter(private val drmList: List) : RecyclerView.Adapte
ViewCompat.setTransitionName(layout, "$drmName")
layout.setOnClickListener {
- val activity = (itemView.context as MainActivity)
+ val context = layout.context
+ val activity = if (context is MainActivity) context
+ else (layout.context as ContextThemeWrapper).baseContext as MainActivity
// Do not create the same fragment again.
activity.supportFragmentManager
@@ -117,6 +121,11 @@ class DrmAdapter(private val drmList: List) : RecyclerView.Adapte
fragment.sharedElementEnterTransition = buildContainerTransform(layout, true)
fragment.sharedElementReturnTransition = buildContainerTransform(layout, false)
}
+ fragment.searchListenerDestroyedListener = object : SearchListenerDestroyedListener {
+ override fun onSearchListenerDestroyed(queryTextListener: SearchView.OnQueryTextListener) {
+ activity.searchListeners.remove(queryTextListener)
+ }
+ }
}
val existingFragment = activity.searchListeners.find { it is DetailsFragment }
diff --git a/app/src/mobile/java/com/parseus/codecinfo/ui/adapters/PagerAdapter.kt b/app/src/mobile/java/com/parseus/codecinfo/ui/adapters/PagerAdapter.kt
index d85899a0..530f050f 100644
--- a/app/src/mobile/java/com/parseus/codecinfo/ui/adapters/PagerAdapter.kt
+++ b/app/src/mobile/java/com/parseus/codecinfo/ui/adapters/PagerAdapter.kt
@@ -9,6 +9,10 @@ import androidx.viewpager2.adapter.FragmentStateAdapter
import com.parseus.codecinfo.data.InfoType
import com.parseus.codecinfo.ui.fragments.ItemFragment
+interface SearchListenerDestroyedListener {
+ fun onSearchListenerDestroyed(queryTextListener: SearchView.OnQueryTextListener)
+}
+
class PagerAdapter(fragmentManager: FragmentManager,
lifecycle: Lifecycle,
private val searchListenerList: MutableList)
@@ -16,11 +20,17 @@ class PagerAdapter(fragmentManager: FragmentManager,
override fun createFragment(position: Int): Fragment {
return ItemFragment().apply {
+ searchListenerDestroyedListener = object : SearchListenerDestroyedListener {
+ override fun onSearchListenerDestroyed(queryTextListener: SearchView.OnQueryTextListener) {
+ searchListenerList.remove(queryTextListener)
+ }
+ }
+
val bundle = Bundle()
bundle.putInt("infoType", position)
arguments = bundle
val existingFragment = searchListenerList.find {
- it is ItemFragment && it.requireArguments().getInt("infoType") == position
+ it is ItemFragment && it.requireArguments().getInt("infoType") == position
}
if (existingFragment != null) {
searchListenerList.remove(existingFragment)
diff --git a/app/src/mobile/java/com/parseus/codecinfo/ui/fragments/DetailsFragment.kt b/app/src/mobile/java/com/parseus/codecinfo/ui/fragments/DetailsFragment.kt
index cf49cb3a..fd521562 100644
--- a/app/src/mobile/java/com/parseus/codecinfo/ui/fragments/DetailsFragment.kt
+++ b/app/src/mobile/java/com/parseus/codecinfo/ui/fragments/DetailsFragment.kt
@@ -1,12 +1,15 @@
package com.parseus.codecinfo.ui.fragments
+import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.widget.TextView
import androidx.appcompat.widget.SearchView
import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
+import androidx.core.widget.NestedScrollView
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
@@ -16,17 +19,21 @@ import com.parseus.codecinfo.data.drm.DrmVendor
import com.parseus.codecinfo.data.drm.getDetailedDrmInfo
import com.parseus.codecinfo.data.knownproblems.KNOWN_PROBLEMS_DB
import com.parseus.codecinfo.databinding.ItemDetailsFragmentLayoutBinding
-import com.parseus.codecinfo.ui.MainActivity
+import com.parseus.codecinfo.ui.ItemDetailsHeaderView
import com.parseus.codecinfo.ui.adapters.DetailsAdapter
+import com.parseus.codecinfo.ui.adapters.SearchListenerDestroyedListener
import com.parseus.codecinfo.ui.expandablelist.ExpandableItemAdapter
import com.parseus.codecinfo.ui.expandablelist.ExpandableItemAnimator
-import com.parseus.codecinfo.utils.isTv
+import com.parseus.codecinfo.utils.getAttributeColor
+import com.parseus.codecinfo.utils.isInTwoPaneMode
import java.util.*
class DetailsFragment : Fragment(), SearchView.OnQueryTextListener {
private var _binding: ItemDetailsFragmentLayoutBinding? = null
- private val binding get() = _binding!!
+ internal val binding get() = _binding!!
+
+ var searchListenerDestroyedListener: SearchListenerDestroyedListener? = null
private lateinit var propertyList: List
@@ -42,9 +49,8 @@ class DetailsFragment : Fragment(), SearchView.OnQueryTextListener {
}
override fun onDestroyView() {
- (requireActivity() as? MainActivity)?.apply {
- searchListeners.remove(this)
- }
+ searchListenerDestroyedListener?.onSearchListenerDestroyed(this)
+ searchListenerDestroyedListener = null
_binding = null
super.onDestroyView()
}
@@ -52,21 +58,23 @@ class DetailsFragment : Fragment(), SearchView.OnQueryTextListener {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- if (requireContext().isTv()) {
- requireActivity().intent?.let {
- codecId = it.getStringExtra("codecId")
- codecName = it.getStringExtra("codecName")
- drmName = it.getStringExtra("drmName")
- drmUuid = it.getSerializableExtra("drmUuid") as UUID?
- }
- } else {
- val bundle = savedInstanceState ?: arguments
- bundle?.let {
- codecId = it.getString("codecId")
- codecName = it.getString("codecName")
- drmName = it.getString("drmName")
- drmUuid = it.getSerializable("drmUuid") as UUID?
- }
+ if (!requireContext().isInTwoPaneMode()) {
+ // Apply background color only on mobile to reduce overdraw on bigger devices
+ binding.endRoot.setBackgroundColor(requireContext().getAttributeColor(com.google.android.material.R.attr.colorSurface))
+ }
+
+ val bundle = savedInstanceState ?: arguments
+ bundle?.let {
+ codecId = it.getString("codecId")
+ codecName = it.getString("codecName")
+ drmName = it.getString("drmName")
+ drmUuid = it.getSerializable("drmUuid") as UUID?
+ }
+
+ if (Build.VERSION.SDK_INT >= 21) {
+ binding.itemDetailsContent.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener {
+ _, _, scrollY, _, _ -> (binding.fullCodecInfoName as ItemDetailsHeaderView).isHeaderLifted = scrollY > 0
+ })
}
if (codecName != null && KNOWN_PROBLEMS_DB.isNotEmpty()) {
@@ -89,6 +97,7 @@ class DetailsFragment : Fragment(), SearchView.OnQueryTextListener {
codecId != null && codecName != null ->
getDetailedCodecInfo(requireContext(), codecId!!, codecName!!)
drmName != null && drmUuid != null ->
+ //noinspection NewApi
getDetailedDrmInfo(requireContext(), DrmVendor.getFromUuid(drmUuid!!))
else -> emptyList()
}
@@ -96,7 +105,8 @@ class DetailsFragment : Fragment(), SearchView.OnQueryTextListener {
}
private fun getFullDetails() {
- binding.fullCodecInfoName.text = codecName ?: drmName
+ @Suppress("USELESS_CAST")
+ (binding.fullCodecInfoName as TextView).text = codecName ?: drmName
val detailsAdapter = DetailsAdapter()
detailsAdapter.add(propertyList)
diff --git a/app/src/mobile/java/com/parseus/codecinfo/ui/fragments/ItemFragment.kt b/app/src/mobile/java/com/parseus/codecinfo/ui/fragments/ItemFragment.kt
index bdd90369..b26e2673 100644
--- a/app/src/mobile/java/com/parseus/codecinfo/ui/fragments/ItemFragment.kt
+++ b/app/src/mobile/java/com/parseus/codecinfo/ui/fragments/ItemFragment.kt
@@ -1,5 +1,6 @@
package com.parseus.codecinfo.ui.fragments
+import android.annotation.SuppressLint
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -19,6 +20,7 @@ import com.parseus.codecinfo.data.drm.getSimpleDrmInfoList
import com.parseus.codecinfo.databinding.TabContentLayoutBinding
import com.parseus.codecinfo.ui.adapters.CodecAdapter
import com.parseus.codecinfo.ui.adapters.DrmAdapter
+import com.parseus.codecinfo.ui.adapters.SearchListenerDestroyedListener
internal var emptyListInformed = false
@@ -29,6 +31,8 @@ class ItemFragment : Fragment(), SearchView.OnQueryTextListener {
private var emptyList = false
+ var searchListenerDestroyedListener: SearchListenerDestroyedListener? = null
+
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = TabContentLayoutBinding.inflate(inflater, container, false)
setHasOptionsMenu(true)
@@ -36,10 +40,14 @@ class ItemFragment : Fragment(), SearchView.OnQueryTextListener {
}
override fun onDestroyView() {
- super.onDestroyView()
+ searchListenerDestroyedListener?.onSearchListenerDestroyed(this)
+ searchListenerDestroyedListener = null
_binding = null
+
+ super.onDestroyView()
}
+ @SuppressLint("NewApi")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -91,6 +99,7 @@ class ItemFragment : Fragment(), SearchView.OnQueryTextListener {
return true
}
+ @SuppressLint("NewApi")
private fun handleSearch(query: String) {
if (emptyList) {
return
diff --git a/app/src/mobile/java/com/parseus/codecinfo/ui/fragments/MainFragment.kt b/app/src/mobile/java/com/parseus/codecinfo/ui/fragments/MainFragment.kt
index f93e4589..da186144 100644
--- a/app/src/mobile/java/com/parseus/codecinfo/ui/fragments/MainFragment.kt
+++ b/app/src/mobile/java/com/parseus/codecinfo/ui/fragments/MainFragment.kt
@@ -8,6 +8,7 @@ import androidx.appcompat.content.res.AppCompatResources
import androidx.fragment.app.Fragment
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
+import com.parseus.codecinfo.R
import com.parseus.codecinfo.data.InfoType
import com.parseus.codecinfo.databinding.FragmentMainBinding
import com.parseus.codecinfo.ui.MainActivity
@@ -28,26 +29,70 @@ class MainFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- val tabs = binding.tabLayout
- tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
- override fun onTabSelected(tab: TabLayout.Tab) {
- InfoType.currentInfoType = InfoType.fromInt(tab.position)
- }
- override fun onTabUnselected(tab: TabLayout.Tab) {}
- override fun onTabReselected(tab: TabLayout.Tab) {}
- })
- val viewPager = binding.pager
- val pagerAdapter = PagerAdapter(childFragmentManager, viewLifecycleOwner.lifecycle,
+ binding.tabLayout?.let { tabs ->
+ tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
+ override fun onTabSelected(tab: TabLayout.Tab) {
+ InfoType.currentInfoType = InfoType.fromInt(tab.position)
+ }
+ override fun onTabUnselected(tab: TabLayout.Tab) {}
+ override fun onTabReselected(tab: TabLayout.Tab) {}
+ })
+
+ val viewPager = binding.pager!!
+ val pagerAdapter = PagerAdapter(childFragmentManager, viewLifecycleOwner.lifecycle,
(activity as? MainActivity)?.searchListeners ?: mutableListOf())
- viewPager.adapter = pagerAdapter
- TabLayoutMediator(tabs, viewPager) { tab, position ->
- val infoType = InfoType.fromInt(position)
- tab.contentDescription = getString(infoType.tabTextResId)
- tab.icon = AppCompatResources.getDrawable(requireContext(), infoType.tabIconResId)
- tab.text = getString(infoType.tabTextResId)
- }.attach()
-
- initializeSamsungGesture(requireContext(), viewPager, tabs)
+ viewPager.adapter = pagerAdapter
+
+ TabLayoutMediator(tabs, viewPager) { tab, position ->
+ val infoType = InfoType.fromInt(position)
+ tab.contentDescription = getString(infoType.tabTextResId)
+ tab.icon = AppCompatResources.getDrawable(requireContext(), infoType.tabIconResId)
+ tab.text = getString(infoType.tabTextResId)
+ }.attach()
+
+ initializeSamsungGesture(requireContext(), viewPager, tabs)
+ }
+
+ binding.navigationRail?.let { navigationRail ->
+ addFragmentToViewHierarchy()
+
+ navigationRail.setOnItemSelectedListener { item ->
+ when (item.itemId) {
+ R.id.audio -> InfoType.currentInfoType = InfoType.Audio
+ R.id.video -> InfoType.currentInfoType = InfoType.Video
+ R.id.drm -> InfoType.currentInfoType = InfoType.DRM
+ }
+
+ addFragmentToViewHierarchy()
+
+ true
+ }
+ }
+ }
+
+ private fun addFragmentToViewHierarchy() {
+ parentFragmentManager.beginTransaction()
+ .replace(R.id.itemFragment, createInfoFragment())
+ .commit()
+ }
+
+ private fun createInfoFragment(): Fragment {
+ return ItemFragment().apply {
+ val bundle = Bundle()
+ bundle.putInt("infoType", InfoType.currentInfoType.tabPosition)
+ arguments = bundle
+ if (this@MainFragment.activity as? MainActivity != null) {
+ val searchListenerList = (this@MainFragment.activity as? MainActivity)!!.searchListeners
+ val existingFragment = searchListenerList.find {
+ it is ItemFragment && (it.requireArguments().getInt("infoType")
+ == InfoType.currentInfoType.tabPosition)
+ }
+ if (existingFragment != null) {
+ searchListenerList.remove(existingFragment)
+ }
+ searchListenerList.add(this)
+ }
+ }
}
override fun onDestroyView() {
diff --git a/app/src/main/java/com/parseus/codecinfo/ui/settings/DarkTheme.kt b/app/src/mobile/java/com/parseus/codecinfo/ui/settings/DarkTheme.kt
similarity index 100%
rename from app/src/main/java/com/parseus/codecinfo/ui/settings/DarkTheme.kt
rename to app/src/mobile/java/com/parseus/codecinfo/ui/settings/DarkTheme.kt
diff --git a/app/src/mobile/java/com/parseus/codecinfo/ui/settings/SettingsActivity.kt b/app/src/mobile/java/com/parseus/codecinfo/ui/settings/SettingsActivity.kt
index 7bec1c02..f5edd77a 100644
--- a/app/src/mobile/java/com/parseus/codecinfo/ui/settings/SettingsActivity.kt
+++ b/app/src/mobile/java/com/parseus/codecinfo/ui/settings/SettingsActivity.kt
@@ -35,7 +35,7 @@ class SettingsActivity : AppCompatActivity() {
private lateinit var binding: SettingsMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
- setTheme(R.style.AppTheme)
+ setTheme(R.style.Theme_CodecInfo)
super.onCreate(savedInstanceState)
if (Build.VERSION.SDK_INT >= 21) {
diff --git a/app/src/main/java/com/parseus/codecinfo/utils/ShareUtils.kt b/app/src/mobile/java/com/parseus/codecinfo/utils/ShareUtils.kt
similarity index 82%
rename from app/src/main/java/com/parseus/codecinfo/utils/ShareUtils.kt
rename to app/src/mobile/java/com/parseus/codecinfo/utils/ShareUtils.kt
index 2651a5bf..03435a4a 100644
--- a/app/src/main/java/com/parseus/codecinfo/utils/ShareUtils.kt
+++ b/app/src/mobile/java/com/parseus/codecinfo/utils/ShareUtils.kt
@@ -1,6 +1,8 @@
package com.parseus.codecinfo.utils
import android.content.Context
+import android.os.Build
+import androidx.annotation.RequiresApi
import com.parseus.codecinfo.R
import com.parseus.codecinfo.data.InfoType
import com.parseus.codecinfo.data.codecinfo.getDetailedCodecInfo
@@ -18,7 +20,7 @@ fun getItemListString(context: Context): String {
val codecSimpleInfoList = getSimpleCodecInfoList(context, true)
codecSimpleInfoList.addAll(getSimpleCodecInfoList(context, false))
codecSimpleInfoList.forEach { builder.append("$it\n") }
- } else {
+ } else if (Build.VERSION.SDK_INT >= 18) {
builder.append("${context.getString(R.string.drm_list)}:\n\n")
getSimpleDrmInfoList(context).forEach { builder.append("$it\n") }
}
@@ -38,10 +40,12 @@ fun getAllInfoString(context: Context): String {
getDetailedCodecInfo(context, info.codecId, info.codecName).forEach { builder.append("$it\n") }
}
- builder.append("\n\n${context.getString(R.string.drm_list)}:\n")
- getSimpleDrmInfoList(context).forEach { infoItem ->
- builder.append("\n$infoItem\n")
- getDetailedDrmInfo(context, DrmVendor.getFromUuid(infoItem.drmUuid)).forEach { builder.append("$it\n") }
+ if (Build.VERSION.SDK_INT >= 18) {
+ builder.append("\n\n${context.getString(R.string.drm_list)}:\n")
+ getSimpleDrmInfoList(context).forEach { infoItem ->
+ builder.append("\n$infoItem\n")
+ getDetailedDrmInfo(context, DrmVendor.getFromUuid(infoItem.drmUuid)).forEach { builder.append("$it\n") }
+ }
}
return builder.toString()
@@ -56,6 +60,7 @@ fun getSelectedCodecInfoString(context: Context, codecId: String, codecName: Str
return builder.toString()
}
+@RequiresApi(18)
fun getSelectedDrmInfoString(context: Context, drmName: String, drmUuid: UUID): String {
val builder = StringBuilder()
builder.append("${context.getString(R.string.drm_details)}: $drmName\n\n")
diff --git a/app/src/mobile/res/animator-v21/item_details_header_state_list_animator.xml b/app/src/mobile/res/animator-v21/item_details_header_state_list_animator.xml
new file mode 100644
index 00000000..9466d470
--- /dev/null
+++ b/app/src/mobile/res/animator-v21/item_details_header_state_list_animator.xml
@@ -0,0 +1,30 @@
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/color/error_text_tint_selector.xml b/app/src/mobile/res/color/error_text_tint_selector.xml
similarity index 100%
rename from app/src/main/res/color/error_text_tint_selector.xml
rename to app/src/mobile/res/color/error_text_tint_selector.xml
diff --git a/app/src/main/res/drawable/ic_email.xml b/app/src/mobile/res/drawable/ic_email.xml
similarity index 100%
rename from app/src/main/res/drawable/ic_email.xml
rename to app/src/mobile/res/drawable/ic_email.xml
diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/mobile/res/drawable/ic_share.xml
similarity index 100%
rename from app/src/main/res/drawable/ic_share.xml
rename to app/src/mobile/res/drawable/ic_share.xml
diff --git a/app/src/mobile/res/layout-sw800dp-land/fragment_main.xml b/app/src/mobile/res/layout-sw800dp-land/fragment_main.xml
new file mode 100644
index 00000000..1ed11e05
--- /dev/null
+++ b/app/src/mobile/res/layout-sw800dp-land/fragment_main.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/mobile/res/layout-v21/item_details_fragment_layout.xml b/app/src/mobile/res/layout-v21/item_details_fragment_layout.xml
new file mode 100644
index 00000000..eeaecdf6
--- /dev/null
+++ b/app/src/mobile/res/layout-v21/item_details_fragment_layout.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/mobile/res/layout-w511dp/activity_main.xml b/app/src/mobile/res/layout-w511dp/activity_main.xml
index bf359dfb..45fa4e69 100644
--- a/app/src/mobile/res/layout-w511dp/activity_main.xml
+++ b/app/src/mobile/res/layout-w511dp/activity_main.xml
@@ -11,7 +11,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
- app:layout_constraintGuide_percent="0.4" />
+ app:layout_constraintGuide_percent="@dimen/separator_guideline_percent" />
+ android:layout_height="wrap_content"
+ tools:viewBindingIgnore="true">
-
-
-
-
-
+ android:paddingLeft="@dimen/list_content_horizontal_padding"
+ android:paddingRight="@dimen/list_content_horizontal_padding"
+ android:paddingBottom="@dimen/list_content_bottom_padding"
+ tools:ignore="SelectableText">
-
-
-
-
+ android:text="@string/more_info"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/codec_full_name"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintVertical_bias="0.0"/>
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/mobile/res/layout/drm_adapter_row.xml b/app/src/mobile/res/layout/drm_adapter_row.xml
index 4dac47c6..2fc4cd95 100644
--- a/app/src/mobile/res/layout/drm_adapter_row.xml
+++ b/app/src/mobile/res/layout/drm_adapter_row.xml
@@ -1,70 +1,52 @@
-
+ android:textColor="?attr/colorPrimary"/>
+ app:autoSizeMinTextSize="8sp"
+ app:autoSizeMaxTextSize="16sp"
+ app:autoSizeStepGranularity="1sp"
+ app:autoSizeTextType="uniform"
+ tools:text="DRM name" />
-
-
+ android:text="@string/more_info"/>
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/expandable_item_content.xml b/app/src/mobile/res/layout/expandable_item_content.xml
similarity index 79%
rename from app/src/main/res/layout/expandable_item_content.xml
rename to app/src/mobile/res/layout/expandable_item_content.xml
index b4193111..ebc77236 100644
--- a/app/src/main/res/layout/expandable_item_content.xml
+++ b/app/src/mobile/res/layout/expandable_item_content.xml
@@ -5,16 +5,16 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/list_content_padding"
- android:layout_marginRight="@dimen/list_content_padding"
- android:layout_marginBottom="@dimen/list_content_padding"
+ android:layout_marginLeft="@dimen/list_content_horizontal_padding"
+ android:layout_marginRight="@dimen/list_content_horizontal_padding"
+ android:layout_marginBottom="@dimen/list_content_horizontal_padding"
android:importantForAccessibility="yes"
android:focusable="true"
android:screenReaderFocusable="true"
tools:ignore="UnusedAttribute">
-
-
-
-
diff --git a/app/src/mobile/res/layout/expandable_item_header.xml b/app/src/mobile/res/layout/expandable_item_header.xml
new file mode 100644
index 00000000..60293f4f
--- /dev/null
+++ b/app/src/mobile/res/layout/expandable_item_header.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/mobile/res/layout/fragment_main.xml b/app/src/mobile/res/layout/fragment_main.xml
index b9f29f7c..1156dbb7 100644
--- a/app/src/mobile/res/layout/fragment_main.xml
+++ b/app/src/mobile/res/layout/fragment_main.xml
@@ -10,6 +10,7 @@
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ app:tabMode="auto"
app:tabInlineLabel="true" />
+ android:paddingBottom="@dimen/list_content_horizontal_padding"
+ android:paddingLeft="@dimen/list_content_horizontal_padding"
+ android:paddingRight="@dimen/list_content_horizontal_padding"
+ tools:ignore="SelectableText">
-
-
+ android:orientation="vertical">
-
+ tools:ignore="SelectableText" />
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/app_bar_menu.xml b/app/src/mobile/res/menu/app_bar_menu.xml
similarity index 100%
rename from app/src/main/res/menu/app_bar_menu.xml
rename to app/src/mobile/res/menu/app_bar_menu.xml
diff --git a/app/src/mobile/res/menu/navigation_rail_menu.xml b/app/src/mobile/res/menu/navigation_rail_menu.xml
new file mode 100644
index 00000000..20baade1
--- /dev/null
+++ b/app/src/mobile/res/menu/navigation_rail_menu.xml
@@ -0,0 +1,16 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/mobile/res/mipmap-anydpi-v26/ic_launcher_round.xml
similarity index 100%
rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
rename to app/src/mobile/res/mipmap-anydpi-v26/ic_launcher_round.xml
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/mobile/res/mipmap-hdpi/ic_launcher_round.png
similarity index 100%
rename from app/src/main/res/mipmap-hdpi/ic_launcher_round.png
rename to app/src/mobile/res/mipmap-hdpi/ic_launcher_round.png
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/mobile/res/mipmap-mdpi/ic_launcher_round.png
similarity index 100%
rename from app/src/main/res/mipmap-mdpi/ic_launcher_round.png
rename to app/src/mobile/res/mipmap-mdpi/ic_launcher_round.png
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/mobile/res/mipmap-xhdpi/ic_launcher_round.png
similarity index 100%
rename from app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
rename to app/src/mobile/res/mipmap-xhdpi/ic_launcher_round.png
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/mobile/res/mipmap-xxhdpi/ic_launcher_round.png
similarity index 100%
rename from app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
rename to app/src/mobile/res/mipmap-xxhdpi/ic_launcher_round.png
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/mobile/res/mipmap-xxxhdpi/ic_launcher_round.png
similarity index 100%
rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
rename to app/src/mobile/res/mipmap-xxxhdpi/ic_launcher_round.png
diff --git a/app/src/mobile/res/values-night/dimens.xml b/app/src/mobile/res/values-night/dimens.xml
deleted file mode 100644
index d1aa4c20..00000000
--- a/app/src/mobile/res/values-night/dimens.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
- 0dp
-
\ No newline at end of file
diff --git a/app/src/mobile/res/values-night/themes.xml b/app/src/mobile/res/values-night/themes.xml
index 23b027d4..6795843d 100644
--- a/app/src/mobile/res/values-night/themes.xml
+++ b/app/src/mobile/res/values-night/themes.xml
@@ -1,18 +1,10 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/mobile/res/values-sw800dp-land/floats.xml b/app/src/mobile/res/values-sw800dp-land/floats.xml
new file mode 100644
index 00000000..b56843fa
--- /dev/null
+++ b/app/src/mobile/res/values-sw800dp-land/floats.xml
@@ -0,0 +1,4 @@
+
+
+ - 0.45
+
\ No newline at end of file
diff --git a/app/src/mobile/res/values-v21/themes.xml b/app/src/mobile/res/values-v21/themes.xml
new file mode 100644
index 00000000..f442f6dc
--- /dev/null
+++ b/app/src/mobile/res/values-v21/themes.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/mobile/res/values-v27/themes.xml b/app/src/mobile/res/values-v27/themes.xml
new file mode 100644
index 00000000..f78d8087
--- /dev/null
+++ b/app/src/mobile/res/values-v27/themes.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/mobile/res/values-w511dp/dimens.xml b/app/src/mobile/res/values-w511dp/dimens.xml
index 004f16d7..9374c63d 100644
--- a/app/src/mobile/res/values-w511dp/dimens.xml
+++ b/app/src/mobile/res/values-w511dp/dimens.xml
@@ -1,4 +1,6 @@
72dp
+ 24dp
+ 16dp
\ No newline at end of file
diff --git a/app/src/mobile/res/values/attrs.xml b/app/src/mobile/res/values/attrs.xml
new file mode 100644
index 00000000..72303323
--- /dev/null
+++ b/app/src/mobile/res/values/attrs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/mobile/res/values/dimens.xml b/app/src/mobile/res/values/dimens.xml
index 1e1a93d3..a56f5b98 100644
--- a/app/src/mobile/res/values/dimens.xml
+++ b/app/src/mobile/res/values/dimens.xml
@@ -1,8 +1,9 @@
- 96dp
+ 88dp
+ 0dp
+ 0dp
8dp
- 4dp
24dp
diff --git a/app/src/mobile/res/values/floats.xml b/app/src/mobile/res/values/floats.xml
new file mode 100644
index 00000000..94b80cb6
--- /dev/null
+++ b/app/src/mobile/res/values/floats.xml
@@ -0,0 +1,5 @@
+
+
+ - 0.87
+ - 0.4
+
\ No newline at end of file
diff --git a/app/src/mobile/res/values/strings.xml b/app/src/mobile/res/values/strings.xml
new file mode 100644
index 00000000..791c8a68
--- /dev/null
+++ b/app/src/mobile/res/values/strings.xml
@@ -0,0 +1,29 @@
+
+
+ Close details
+
+ Share
+ Choose info to share
+ Codec list
+ Selected codec details
+ All codecs and DRMs with details
+
+ parseus.dev@gmail.com
+ Feedback
+ Send feedback via…
+ No apps can perform this action.
+ No apps can perform this action. Email address was copied to the clipboard.
+
+ Light
+ Dark
+ Set by Battery Saver
+ System default
+
+ Tap here to see more info…
+
+ item_details
+
+ %1$s codec %2$d - %3$s: %4$s for %5$s
+ %1$s codec %2$d - %3$s: %4$s for %5$s. Known issue detected!
+ DRM %1$d: %2$s
+
\ No newline at end of file
diff --git a/app/src/mobile/res/values/styles.xml b/app/src/mobile/res/values/styles.xml
new file mode 100644
index 00000000..3dddd69e
--- /dev/null
+++ b/app/src/mobile/res/values/styles.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/mobile/res/values/themes.xml b/app/src/mobile/res/values/themes.xml
new file mode 100644
index 00000000..2536f473
--- /dev/null
+++ b/app/src/mobile/res/values/themes.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/mobile/res/xml/file_paths.xml
similarity index 100%
rename from app/src/main/res/xml/file_paths.xml
rename to app/src/mobile/res/xml/file_paths.xml
diff --git a/app/src/nonFreeMobile/java/com/parseus/codecinfo/utils/ReflectionUtils.kt b/app/src/nonFreeMobile/java/com/parseus/codecinfo/utils/ReflectionUtils.kt
new file mode 100644
index 00000000..83e27346
--- /dev/null
+++ b/app/src/nonFreeMobile/java/com/parseus/codecinfo/utils/ReflectionUtils.kt
@@ -0,0 +1,6 @@
+package com.parseus.codecinfo.utils
+
+import android.os.Build
+
+val CAN_USE_REFLECTION_FOR_MCAPABILITIESINFO = Build.VERSION.SDK_INT < 28
+fun disableApiBlacklistOnPie() {}
\ No newline at end of file
diff --git a/app/src/standard/assets/libraries.html b/app/src/standardMobile/assets/libraries.html
similarity index 100%
rename from app/src/standard/assets/libraries.html
rename to app/src/standardMobile/assets/libraries.html
diff --git a/app/src/standardMobile/java/com/parseus/codecinfo/utils/ReflectionUtils.kt b/app/src/standardMobile/java/com/parseus/codecinfo/utils/ReflectionUtils.kt
new file mode 100644
index 00000000..41342b9f
--- /dev/null
+++ b/app/src/standardMobile/java/com/parseus/codecinfo/utils/ReflectionUtils.kt
@@ -0,0 +1,20 @@
+package com.parseus.codecinfo.utils
+
+import android.os.Build
+import java.lang.reflect.Method
+
+val CAN_USE_REFLECTION_FOR_MCAPABILITIESINFO = Build.VERSION.SDK_INT < 29
+
+fun disableApiBlacklistOnPie() {
+ if (Build.VERSION.SDK_INT != 28) {
+ return
+ }
+
+ val forName = Class::class.java.getDeclaredMethod("forName", String::class.java)
+ val getDeclaredMethod = Class::class.java.getDeclaredMethod("getDeclaredMethod", String::class.java, arrayOf>()::class.java)
+ val vmRuntimeClass = forName.invoke(null, "dalvik.system.VMRuntime") as Class<*>
+ val getRuntime = getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null) as Method
+ val setHiddenApiExemptions = getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", arrayOf(arrayOf()::class.java)) as Method
+ val vmRuntime = getRuntime.invoke(null)
+ setHiddenApiExemptions.invoke(vmRuntime, arrayOf("L"))
+}
\ No newline at end of file
diff --git a/app/src/standard/java/com/parseus/codecinfo/utils/ThirdPartyUtils.kt b/app/src/standardMobile/java/com/parseus/codecinfo/utils/ThirdPartyUtils.kt
similarity index 100%
rename from app/src/standard/java/com/parseus/codecinfo/utils/ThirdPartyUtils.kt
rename to app/src/standardMobile/java/com/parseus/codecinfo/utils/ThirdPartyUtils.kt
diff --git a/app/src/tv/AndroidManifest.xml b/app/src/tv/AndroidManifest.xml
index 0c9653d1..4e904b3d 100644
--- a/app/src/tv/AndroidManifest.xml
+++ b/app/src/tv/AndroidManifest.xml
@@ -10,8 +10,9 @@
+ android:theme="@style/Theme.CodecInfo">
@@ -19,19 +20,19 @@
diff --git a/app/src/tv/java/com/parseus/codecinfo/ui/CodecPresenter.kt b/app/src/tv/java/com/parseus/codecinfo/ui/CodecPresenter.kt
index 0eb6dcf7..bf034f29 100644
--- a/app/src/tv/java/com/parseus/codecinfo/ui/CodecPresenter.kt
+++ b/app/src/tv/java/com/parseus/codecinfo/ui/CodecPresenter.kt
@@ -47,8 +47,7 @@ class CodecPresenter(@DrawableRes private val drawable: Int) : Presenter() {
it.isAffected(context, info.codecName)
}
if (knownProblems.isNotEmpty()) {
- badgeImage = AppCompatResources.getDrawable(context,
- com.google.android.material.R.drawable.mtrl_ic_error)
+ badgeImage = AppCompatResources.getDrawable(context, R.drawable.ic_error)
}
}
}
diff --git a/app/src/tv/java/com/parseus/codecinfo/ui/fragments/DetailsFragment.kt b/app/src/tv/java/com/parseus/codecinfo/ui/fragments/DetailsFragment.kt
index e0f65239..31e2f92f 100644
--- a/app/src/tv/java/com/parseus/codecinfo/ui/fragments/DetailsFragment.kt
+++ b/app/src/tv/java/com/parseus/codecinfo/ui/fragments/DetailsFragment.kt
@@ -48,21 +48,11 @@ class DetailsFragment : Fragment(), SearchView.OnQueryTextListener {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- if (requireContext().isTv()) {
- requireActivity().intent?.let {
- codecId = it.getStringExtra("codecId")
- codecName = it.getStringExtra("codecName")
- drmName = it.getStringExtra("drmName")
- drmUuid = it.getSerializableExtra("drmUuid") as UUID?
- }
- } else {
- val bundle = savedInstanceState ?: arguments
- bundle?.let {
- codecId = it.getString("codecId")
- codecName = it.getString("codecName")
- drmName = it.getString("drmName")
- drmUuid = it.getSerializable("drmUuid") as UUID?
- }
+ requireActivity().intent?.let {
+ codecId = it.getStringExtra("codecId")
+ codecName = it.getStringExtra("codecName")
+ drmName = it.getStringExtra("drmName")
+ drmUuid = it.getSerializableExtra("drmUuid") as UUID?
}
if (codecName != null && KNOWN_PROBLEMS_DB.isNotEmpty()) {
diff --git a/app/src/tv/java/com/parseus/codecinfo/utils/ReflectionUtils.kt b/app/src/tv/java/com/parseus/codecinfo/utils/ReflectionUtils.kt
new file mode 100644
index 00000000..83e27346
--- /dev/null
+++ b/app/src/tv/java/com/parseus/codecinfo/utils/ReflectionUtils.kt
@@ -0,0 +1,6 @@
+package com.parseus.codecinfo.utils
+
+import android.os.Build
+
+val CAN_USE_REFLECTION_FOR_MCAPABILITIESINFO = Build.VERSION.SDK_INT < 28
+fun disableApiBlacklistOnPie() {}
\ No newline at end of file
diff --git a/app/src/tv/res/color/error_text_tint_selector.xml b/app/src/tv/res/color/error_text_tint_selector.xml
new file mode 100644
index 00000000..208322c9
--- /dev/null
+++ b/app/src/tv/res/color/error_text_tint_selector.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/tv/res/drawable/ic_error.xml b/app/src/tv/res/drawable/ic_error.xml
new file mode 100644
index 00000000..5c97db92
--- /dev/null
+++ b/app/src/tv/res/drawable/ic_error.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/app/src/tv/res/layout/expandable_item_content.xml b/app/src/tv/res/layout/expandable_item_content.xml
new file mode 100644
index 00000000..abb43b6a
--- /dev/null
+++ b/app/src/tv/res/layout/expandable_item_content.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/expandable_item_header.xml b/app/src/tv/res/layout/expandable_item_header.xml
similarity index 83%
rename from app/src/main/res/layout/expandable_item_header.xml
rename to app/src/tv/res/layout/expandable_item_header.xml
index 96bd42ce..bd148f76 100644
--- a/app/src/main/res/layout/expandable_item_header.xml
+++ b/app/src/tv/res/layout/expandable_item_header.xml
@@ -15,14 +15,14 @@
tools:ignore="UnusedAttribute">
+ android:paddingBottom="@dimen/list_content_horizontal_padding"
+ android:paddingLeft="@dimen/list_content_horizontal_padding"
+ android:paddingRight="@dimen/list_content_horizontal_padding">
bold
+
+
+
+
+
+
+
+
diff --git a/app/src/tv/res/values/themes.xml b/app/src/tv/res/values/themes.xml
index 71fedc6b..fe56b365 100644
--- a/app/src/tv/res/values/themes.xml
+++ b/app/src/tv/res/values/themes.xml
@@ -1,24 +1,26 @@
-
-
-
-
-
+
+
-
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index ddf22997..f6d2f569 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,16 +1,16 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.4.21'
- ext.leakCanary_version = '2.6'
- ext.moshi_version = '1.11.0'
+ ext.kotlin_version = '1.5.10'
+ ext.leakCanary_version = '2.7'
+ ext.moshi_version = '1.12.0'
repositories {
google()
- jcenter()
+ mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.2.0-beta04'
+ classpath 'com.android.tools.build:gradle:4.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
@@ -21,7 +21,7 @@ buildscript {
allprojects {
repositories {
google()
- jcenter()
+ mavenCentral()
maven { url "https://jitpack.io" }
}
}
diff --git a/gradle.properties b/gradle.properties
index 27bb9e43..8eaaffe2 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,5 +1,4 @@
org.gradle.jvmargs=-Xmx1536m -XX:+UseParallelGC
-org.gradle.vfs.watch=true
android.enableAppCompileTimeRClass=true
android.enableR8.fullMode=true
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 62d4c053..e708b1c0 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 79be759c..3c4101c3 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Thu Oct 15 19:14:14 CEST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https://services.gradle.org/distributions/gradle-6.7.1-all.zip
diff --git a/gradlew b/gradlew
index fbd7c515..4f906e0c 100644
--- a/gradlew
+++ b/gradlew
@@ -130,7 +130,7 @@ fi
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
+
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
diff --git a/gradlew.bat b/gradlew.bat
index 5093609d..107acd32 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -54,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -64,21 +64,6 @@ echo location of your Java installation.
goto fail
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
:execute
@rem Setup the command line
@@ -86,7 +71,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell