Closed courville closed 2 years ago
androidR branch created for Video/MediaLib/FileCoreLibrary
getPath is greylisted reflection denied on API30: See https://github.com/nova-video-player/aos-FileCoreLibrary/commit/e81467beab3e6c47090448674870d8b7bbeb1c46 See https://github.com/nova-video-player/aos-FileCoreLibrary/commit/04839cae17ed8547006c74eec99e660e11cd180e
Pending google play to be ready to manage properly android.permission.MANAGE_EXTERNAL_STORAGE and request exemption.
See https://github.com/nova-video-player/aos-Video/commit/fa42e916de4ffca7758d68e83d8b0f5915d3a1b3
Check https://support.google.com/googleplay/android-developer/answer/9956427 to request exemption.
Exemption requested and denied. For the record here are the elements sent. App functionality requiring the permission (limit 500 chars):
Nova is a video player/manager that catalogs (though MediaStore.Files import) and presents all videos as a structured medialibrary (Movie/TVshow/Anime) after media information scraping (themoviedb/thetvdb cloud services).
It needs to:
- access all videos already present on the device wherever located (internal, SDcard, USB)
- act as a file manager (import/delete/download) for all media files even those not recognized as such by Android: e.g. NFO metadata, SUB/SSA subtitles, XML resume points
Why can't your app follow good confidentiality practices (i.e. Storage Access Framework or Media Store API or Scoped Storage) (limit 500 chars):
Without loss of functionality, scoped storage cannot be used since Nova needs to index all preexisting videos & related files at any location (internal/SDcard/USB)
MediaStoreAPI does not allow managing (read/download/delete) all media files processed today by Nova: e.g. NFO metadata, SUB/SSA subtitle, XML resume points
Storage Access Framework is not compatible with Nova full device media persistent library design capturing overall device content
Nova is open-source and can be audited on github
Less than 30s video explaining the claim: https://home.courville.org/nova_video_player-faq/nova-MANAGE_EXTERNAL_STORAGE-permission.mp4
Generic reject email received from Google without any specific information.
Overall this is a very frustrating experience.
Note that Google failed to implement on Android TV (at least API30 emulator) the required dialog to manage properly android.permission.MANAGE_EXTERNAL_STORAGE
:
2021-07-10 15:25:25.798 4151-4151/org.courville.nova E/AndroidRuntime: FATAL EXCEPTION: main
Process: org.courville.nova, PID: 4151
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION (has extras) }
at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2067)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1727)
at android.app.Activity.startActivityForResult(Activity.java:5320)
at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:574)
at android.app.Activity.startActivityForResult(Activity.java:5278)
at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:560)
at android.app.Activity.startActivity(Activity.java:5664)
at android.app.Activity.startActivity(Activity.java:5617)
at com.archos.mediacenter.video.browser.PermissionChecker$4.onClick(PermissionChecker.java:161)
at androidx.appcompat.app.AlertController$ButtonHandler.handleMessage(AlertController.java:167)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
This is a mess.
Found old issue on issuetracker somehow related https://issuetracker.google.com/issues/136774034 And precious command:
adb shell content query --uri "content://media/external/file" --projection name:_data.
API30debacle plan of record:
In terms of deadline 2021/11/1 for nova cf. https://support.google.com/googleplay/android-developer/answer/9859152#zippy=%2Ctarget-api-level-requirements-for-play-console
API level requirement | Starting date |
---|---|
Android 8.0 (API level 26) | August 1, 2018: Required for new appsNovember 1, 2018: Required for app updates |
Android 9 (API level 28) | August 1, 2019: Required for new appsNovember 1, 2019: Required for app updates |
Android 10 (API level 29)* | August 3, 2020: Required for new appsNovember 2, 2020: Required for app updates |
Android 11 (API level 30)* | August 2, 2021: Required for new appsNovember 1, 2021: Required for app updates |
As mentioned here, it is still possible to use the classic File API, though it is limited to media files only (just like the MediaStore API). The greylisted methods could be possibly replaced by MediaStore.getExternalVolumeNames() (?).
Reading https://stackoverflow.com/questions/56468539/getexternalstoragepublicdirectory-deprecated-in-android-q leads to the conclusion that nova needs to use MediaStore API.
Code sample to implement create/delete/etc... classes compatible with Android Q/R (FileUtilsQ.java
) are available here https://gist.github.com/fiftyonemoon/433b563f652039e32c07d1d629f913fb and mentioned here https://stackoverflow.com/questions/64582269/how-can-i-delete-file-on-android-11-api-30-without-system-confirmation-dialog
This requires however to have proper content://
uri and https://stackoverflow.com/questions/7305504/convert-file-uri-to-content-uri provides some more or less working methods.
Experimenting a bit:
content://media/external_primary/file/##
uricontent://media/external_primary/video/media/###
uriSome useful query methods via adb:
adb shell content query --uri "content://media/external_primary/video/media" --projection _data
adb shell content query --uri "content://media/external/file" --projection _data
To get the content uri, this asynchronous way works:
MediaScannerConnection.scanFile(mContext, new String[]{ uri.getPath() },
null, // mimetypes
new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(String path, Uri uri) {
contentUri = uri;
log.debug("scanFile: contentUri " + contentUri + " for path " + path);
}
});
Note that the hack in ExternalSDFileWriter
make Android believe that the file is an image via insertion in the MediaStore.Images.Media
does not work anymore and will need to be removed from the code.
TODO:
Video/src/main/java/com/archos/mediacenter/video/utils/SubtitlesDownloaderActivity.java:953
and MediaLib/src/com/archos/mediascraper/NfoWriter.java:326
. For this use nova setting "Export all descriptions" to see the FileNotFoundException
errors (open failed: EPERM
). Perhaps use new FileUtilsQ
create method?MediaStore.VOLUME_EXTERNAL
or MediaStore.Video.Media.EXTERNAL_CONTENT_URI
in getContentUri
from FileCoreLibrary/src/com/archos/filecorelibrary/FileUtilsQ.java
. Could be done first doing adb content query on box after indexing.NFO files (text/plain
mime type only https://cs.android.com/android/platform/superproject/+/master:packages/providers/MediaProvider/src/com/android/providers/media/util/MimeUtils.java?q=MimeUtils.java) can only be created in Documents/Download
folders. It does not make sense to prefix them in app private directory getFilesDir()
since nobody would access them. See https://developer.android.com/training/data-storage
Alternative is to use getExternalFilesDir(null) /storage/emulated/0/Android/data/org.courville.nova/files
visible from users and where nova can write.
Links to refresh crash courses on directories: https://gist.github.com/granoeste/5574148 https://medium.com/microsoft-mobile-engineering/scoped-storage-in-android-10-android-11-28d58d989f3c
Some TODO (for me):
API31 targeted for v6.0.30 onward.
VLC 3.4.3 beta 6 available from the public testing channel on Google Play uses the MANAGE_EXTERNAL_STORAGE permission.
@moneytoo thanks for sharing this news. It hurts since I have been denied this privilege by Google. I am glad for vlc to have managed to lobby for it. At least nova complies with the security requirements of Android... /me cries into a pillow
/me having fun looking at https://www.reddit.com/r/androiddev/comments/rmgdis/how_come_vlc_is_allowed_to_use_manage_external/ Thanks @moneytoo
@moneytoo, I just made the connection with just video player (I am slow sorry). FYI nova relies on the old Archos Video Player AVOS C based multimedia engine that used to be the software basis for all Archos multimedia PMPs.
From the VLC folks and for track record https://issuetracker.google.com/issues/143549606
OK just noticed on Google Play console that I have been awarded the android.permission.MANAGE_EXTERNAL_STORAGE
sensitive permission (after it has been denied). It appeared out of the blue somehow.
@moneytoo you should check too (finger crossed).
EDIT: I also checked that I can deploy an internal release with the perm.
Knowing Google, something like that usually sounds too good to be true. But if it sticks, it's great. Could it be because you left a version of an app with such permission in some release channel untouched and they eventually approved it? At least for me, I only see my declaration for this permission in App content section and nothing more.
OK this was indeed too good to be true. After granted deployment it has been cancelled. FTR this is what was indicated on the google play console:
BTW, it's not only VLC possessing such permission, but a "few more" other players at least:
MX Player (com.mxtech.videoplayer.ad)
MX Player Pro (com.mxtech.videoplayer.pro)
VLC (org.videolan.vlc)
OPlayer Lite (com.olimsoft.android.oplayer)
OPlayer (com.olimsoft.android.oplayer.pro)
KMPlayer (com.kmplayer)
XPlayer (video.player.videoplayer)
PLAYit (com.playit.videoplayer)
HD Video Player by iJoysoft (free.online.hd.video.player)
Video Player by Leopard V7 (com.mine.videoplayer)
@moneytoo indeed list is expanding... Not quite sure what is the magic for requesting permission since it has been denied twice. I hate to resort to this, but I might ping some google folks to understand better the process. Please let me know if you find more.
My opinion is that the magic is either support of some not normally indexed file format (.iso, .wmv, .rm, possibly some other subtitle or audio formats) or some advanced file functionality (local p2p file sharing, folder encryption or lockings etc.).
@moneytoo thanks for sharing, have you requested on play console the right?
FTR after downloading a couple (not being exhaustive there) of video players on apkpure (I know...), a simple for i in *apk; do aapt d permissions "$i" | grep '(package|MANAGE)'; done
provides:
package: com.kmplayer
uses-permission: name='android.permission.MANAGE_EXTERNAL_STORAGE'
package: org.xbmc.kodi
uses-permission: name='android.permission.MANAGE_EXTERNAL_STORAGE'
package: com.mxtech.videoplayer.ad
uses-permission: name='android.permission.MANAGE_EXTERNAL_STORAGE'
package: video.player.videoplayer
uses-permission: name='android.permission.MANAGE_EXTERNAL_STORAGE'
package: com.kmp.video
uses-permission: name='android.permission.MANAGE_EXTERNAL_STORAGE'
package: com.mine.videoplayer
uses-permission: name='android.permission.MANAGE_EXTERNAL_STORAGE'
package: org.videolan.vlc
uses-permission: name='android.permission.MANAGE_EXTERNAL_STORAGE'
OK after discussing with Google Developper Support, I was not able to get someone that could help on MANAGE_EXTERNAL_STORAGE permission. However, declaration on Play Console "application content section", the "access to all files" is marked treated and seems enabled. I gave another shot at publishing the nova on internal track and it has not been removed by Google for a week. I reworked the code to grant the permission to be "universally compatible" with Android ecosystem. What I learned is:
What is "fun" is this special case for Android TV.
No wonder that boxes supporting USB storage does not want to migrate to Android 12. Staying on Android 11 waiting for Android 14 is the only way to get apps such as file managers working without fiddling with Android framework introducing some "customizations" forking from a vanilla base.
Couple of references for the record on Android not detecting correctly media files:
In order to target SDK 30 you need:
When launching the app you get this obvious introspection not allowed anymore to solve: