Android media access что это

Хранение данных и файлов

В целом хранение файлов и данных можно условно разделить на две группы: во внутреннем или внешнем хранилище. Но разница между ними довольна тонка. В целом политика Гугла в отношение данных ужесточается с каждой версии системы.

Android поддерживает различные варианты хранения данных и файлов.

  • Специфичные для приложения файлы. Доступ к файлам имеет только приложение, их создавшее. Файлы могут находиться во внутреннем и внешнем хранилище. У других приложений нет доступа (кроме случаев, когда файлы хранятся на внешнем хранилище). Методы getFilesDir(), getCacheDir(), getExternalFilesDir(), getExternalCacheDir(). Разрешений на доступ не требуется. Файлы удаляются, когда приложение удаляется пользователем.
  • Разделяемое хранилище. Приложение может создавать файлы, которыми готово поделиться с другими приложениями — медиафайлы (картинки, видео, аудио), документы. Для медифайлов требуется разрешение READ_EXTERNAL_STORAGE или WRITE_EXTERNAL_STORAGE.
  • Настройки. Хранение простых данных по принципу ключ-значение. Доступно внутри приложения. Реализовано через Jetpack Preferences. Настройки удаляются, когда приложение удаляется пользователем.
  • Базы данных. Хранение данных в SQLite. На данный момент реализовано через библиотеку Room. Доступ только у родного приложения.

В зависимости от ваших потребностей, нужно выбрать нужный вариант хранения данных.

Следует быть осторожным при работе с внутренним и внешним хранилищем. Внутренне хранилище всегда есть в системе, но оно может быть не слишком большим по объёму. Вдобавок к внутреннему хранилищу, устройство может иметь внешнее хранилище. В старых моделях таким хранилищем выступала съёмная SD-карта. Сейчас чаще используют встроенную и недоступную для извлечения флеш-память. Если ваше приложение слишком большое, можно попросить систему устанавливать программу во внешнее хранилище, указав просьбу в манифесте.

В разных версиях Android требования к разрешению для работы с внешним хранилищем постоянно менялись. На данный момент (Android 10, API 29) требования выглядят следующим образом.

Приложение может иметь доступ к собственным файлам, которые находятся во внешнем хранилище. Также может получить доступ к определённым общим файлам на внешнем хранилище.

Доступ к общим файлам достигается через FileProvider API или контент-провайдеры.

Для просмотра файлов через студию используйте инструмент Device File Explorer.

Внешняя карта памяти

Когда появились первые устройства на Android, то практически у всех были внешние карточки памяти, которые вставлялись в телефон. Обычно там хранили фотки, видео и свои файлы. Всё было понятно — были различные методы для доступа к файловой системе. А потом началась чехарда. В телефонах также была и собственная «внешняя» память. Она вроде как и внешняя, но вставлена на заводе и вытащить её пользователь не мог, т.е. практически внутренняя. Затем пошла мода на телефоны, у которых была только такая внутреннее-внешняя карта. Пользователи поворчали, но привыкли. Сейчас встречаются оба варианта. Как правило, у телефонов с спрятанной картой больше памяти и выше степень водонепроницаемости.

Подобные фокусы с картой породили и другую проблему — Гугл озаботился безопасностью файлов и стала думать, как осложнить жизнь разработчику. С выходом каждой новой версии системы компания то давала добро на полный доступ к карточке, то ограничивала, то давала права с ограничениями, то откатывала свои решения назад. Короче, запутались сами и запутали всех.

Попробуем немного разобраться с этим зоопарком. Но помните, что процесс путаницы продолжается.

При подготовке материала я опирался на письма некоторых читателей сайта, которые присылали свои мысли по этому поводу. Спасибо им за структуризацию материала.

Вот что я (кажется) понял, попытавшись загрузить картинку с внешней SD карточки.

External это не External
«EXTERNAL_STORAGE» называется так не потому, что это внешняя память по отношению к устройству, а потому что она выглядит как внешняя память для компьютера, если устройство подключить кабелем к компьютеру. Причём именно выглядит, потому что обмен идёт по протоколу MTP – устройство только показывает компьютеру список папок и файлов, а при необходимости открыть или скопировать файл он специально загружается на компьютер, в отличие от настоящей флешки, файлы которой становятся файлами в файловой системе самого компьютера. Обмен по MTP позволяет устройству продолжать работать, когда оно подключено к компьютеру.

Emulated это не Emulated
Сначала я пытался прочесть файл с карточки на эмуляторе (из этого так ничего и не вышло). Функция getExternalStorageDirectory() давала мне /storage/emulated/0, и я думал, что «emulated» – это потому что на эмуляторе. Но когда я подцепил реальный планшет, слово «emulated» никуда не исчезло. Я стал рыться в интернете и обнаружил, что «Emulated storage is provided by exposing a portion of internal storage through an emulation layer and has been available since Android 3.0.» – то есть это просто кусок внутренней памяти, которая путём какой-то эмуляции делается доступной для пользователя, в отличие от собственно внутренней памяти.

Читайте также:  Find device android device manager

При этом с точки зрения системы доступная для пользователя папка называется /storage/emulated/0, а при подключении к компьютеру по USB это просто одна из двух главных папок устройства – у меня в Windows Explorer она называется Tablet. Вторая папка у меня называется Card, и это и есть настоящая внешняя карточка.

Нет стандартных средств добраться из приложения до файлов на внешней карточке. Все попытки добраться до настоящей внешней карточки делаются с помощью неких трюков. Самое интересное, что я нашел, это статья на http://futurewithdreams.blogspot.com/2014/01/get-external-sdcard-location-in-android.html — парень читает таблицу смонтированных устройств /proc/mounts, таблицу volume daemons /system/etc/vold.fstab, сравнивает их и выбирает те тома, которые оказываются съёмными (с помощью Environment.isExternalStorageRemovable()).

Оказалось, что несистемным приложениям в принципе запрещено напрямую обращаться к съёмной карточке! Похоже, что это было так всегда, но вот начиная с версии Android 6 Marshmallow написано: внешняя карточка может быть определена как Portable либо Adoptable. Adoptable – это как бы «усыновляемая» память которая может быть «adopted», то есть взята в систему (примерно как кот с улицы в дом – это тоже называется to adopt) и использована как внутренняя. Для этого ее надо особым образом отформатировать и не вынимать, иначе не факт, что система продолжит нормально работать.

Portable – это нормальная съёмная карточка, но несистемным приложениям запрещено обращаться из программ к файлам на ней! Вот что написано в https://source.android.com/devices/storage/traditional.html:

Android 6.0 supports portable storage devices which are only connected to the device for a short period of time, like USB flash drives. When a user inserts a new portable device, the platform shows a notification to let them copy or manage the contents of that device. In Android 6.0, any device that is not adopted is considered portable. Because portable storage is connected for only a short time, the platform avoids heavy operations such as media scanning. Third-party apps must go through the Storage Access Framework to interact with files on portable storage; direct access is explicitly blocked for privacy and security reasons.

Если я правильно понял, этот самый Storage Access Framework позволяет работать с документом на карточке через диалог (открыть файл/сохранить файл), а вот прочитать или записать файл на карточке непосредственно из программы невозможно.

Общий вывод – реально из программы можно работать только с файлами на предоставляемой пользователю части встроенной памяти устройства, а на съёмной карточке – нет.

Это напоминает войну Microsoft с пользователями и разработчиками по поводу диска C:, компания уговаривала не устраивать беспорядок в корне этого диска, а ещё лучше — перенести свои файлы на другой диск. Но явных запретов не было.

Состояние на текущий момент

Гугл утверждает, что с версии Android 10 Q стандартный доступ к файлам будет прекращён. Ещё в Android 4.4 появился Storage Access Framework, который и должен стать заменой для работы с файлами.

Методы Environment.getExternalStorageDirectory() и Environment.getExternalStoragePublicDirectory() признаны устаревшими и будут недоступны. Даже если они будут возвращать корректные значения, ими вы не сможете воспользоваться.

В Android 7.0 добавили исключение FileUriExposedException, чтобы разработчики перестали использовать схему file://Uri.

Можно создавать файлы в корневой папке карточки при помощи Environment.getExternalStorageDirectory(), а также папки с вложенными файлами. Если папка уже существует, то у вас не будет доступа на запись (если это не ваша папка).

Если вы что-то записали, то сможете и прочитать. Чужое читать нельзя.

Кстати, разрешения на чтение и запись файлов не требуются, а READ_EXTERNAL_STORAGE и WRITE_EXTERNAL_STORAGE объявлены устаревшими.

Другие приложения не могут получить доступ к файлам вашего приложения. Файлы, которые вы создали через getExternalFilesDir(), доступны через Storage Access Framework, кроме файлов, созданных в корне карточки (что-то я совсем запутался). Ещё можно дать доступ через FileProvider.

При подключении USB-кабеля через getExternalFilesDir(), вы можете увидеть свои файлы и папки, а также файлы и папки пользователя. При этом файлы и папки пользователя на корневой папке вы не увидите. Вам не поможет даже adb или Device File Explorer студии.

Что делать?

Пользуйтесь методами класса Context, типа getExternalFilesDir(), getExternalCacheDir(), getExternalMediaDirs(), getObbDir() и им подобными, чтобы найти место для записи.

Используйте Storage Access Framework.

Используйте MediaStore для мультимедийных файлов.

Используйте FileProvider, чтобы файлы были видимы другим приложениям через ACTION_VIEW/ACTION_SEND.

Android 10: Появился новый флаг android:allowExternalStorageSandbox=»false» и метод Environment.isExternalStorageSandboxed() для работы с песочницей. Флаг android:requestLegacyExternalStorage=»true» для приложений, которые ещё используют старую модель доступа к файлам.

Читайте также:  Qr код outlook android

Как временное решение можно добавить в блок манифеста application атрибут android:requestLegacyExternalStorage=»true», чтобы доступ к файлам был как раньше в Android 4.4-9.0.

Android 11

Если вы создаёте файловый менеджер, то ему нужны возможности для просмотра файлов. Для этого следует установить разрешение MANAGE_EXTERNAL_STORAGE или использовать атрибут android:requestLegacyExternalStorage=»true» (см. выше).

Источник

Android MediaPlayer. Расширяем возможности с помощью прокси


Реализация прокси для стандартного компонента MediaPlayer несёт в себе гораздо больше преимуществ, чем может показаться на первый взгляд. В этой статье подробно рассказывается, как это всё работает и о перспективах развития подобной технологии.

Долгое время я искал наиболее удачную реализацию медиаплеера под андроид для своего приложения Media Library. Я испытывал ExoPlayer. У него нет банальной поддержки flv. На что разработчики сказали, что нет времени на добавление поддержки этого формата. Далее я стал использовать Vitamio. И Vitamio показался сначала более менее подходящим решением, но пообщавшись с его разработчиком Crossle я узнал, что помощи от него не ждать. Баги он не исправляет и вообще уже почти никто не занимается этим проектом. Так как багов было очень много, я вернулся на стандартный плеер. Он мне показался наиболее быстрым и безглючным. Конечно в нём нет столько функций, как в ExoPlayer или Vitamio. Поэтому я начал изучать, как добавить их самостоятельно.
VideoView пользоваться я не стал и сделал кастомный класс плеера. В него я добавил много своих Event-ов на все случаи жизни. Плеер основан на textureView. Искал способ, как заставить плеер играть в фоновом режиме и при пересоздании Activity. С SurfaceView такого не получилось. TextureView — работает отлично. Верти, крути… а музыка играет. В сервис переводить плеер я так и не нашёл причины. А зачем, когда и так всё хорошо работает. Как только причина появиться — сервис будет создан.

Задачи было две простых — создать кеш для плеера и заставить его играть из FTP. Об этом меня попросил один пользователь моего плеера. Ему хочется слушать музыку со своего NASа, который поддерживает FTP протокол.
Как программисту мне понятно, что сначала надо было написать прокси и через это прокси организовать конвертацию HTTP<>FTP запросов и передачу данных. Что я и сделал в своём проекте ImmortalPlayer.

В перспективе эту прокси можно использовать с VItamio (у которого с кэшем всё не так хорошо) и тогда получится совсем комбаин, который играет все форматы и поддерживает все протоколы)), но не рекомендую так делать. Так как разнообразие форматов — это не только польза, но и зло. Для плеера нужна поддержка основных форматов и некоторых второстепенных, а не всех подряд. Это приведёт к чистоте и повышению качества материала у пользователей. Кроме этого поддержка форматов должна быть на системном уровне, встроенными кодеками, а не на уровне плеера. Vitamio — имеет множество багов с рассинхронизацией звука и видео, низкую производительность и увеличивает размер приложения apk на 10-15 мегабайт.

Определяем права доступа:
AndroidManifest.xml

Wake_Lock — для того что бы плеер не прекращал играть, когда устройство находится в спящем режиме.
WRITE_EXTERNAL_STORAGE — для записи кэша на внешний носитель устройства.

Присваиваем новый экземпляр класса переменной proxy. И задаём параметры:
proxy.setPaths(папка куда сохранять кэш, сама ссылка на файл в интернете, размер кэша, количество файлов в кэше, контекст, удалять ли не докаченные файлы?, логин ФТП, пароль ФТП, режим совместимости FTP?);
Получаем путь прокси для плеера String proxyUrl = proxy.getLocalURL();
Стартуем плеер textureView.setVideoPath(proxyUrl);

Прокси стартует уже со строки proxy = new HttpGetProxy();. Есть команда на остановку proxy.stopProxy(). По этой команде закрывается локальный сокет, ожидающий запросов от плеера и после этого завершается Thread прокси. Грубо, но пока не нашёл более мягкого выхода.

Не сложно догадаться, как сделать прокси только для чтения. Что бы ничего не писалось на карту памяти. Пока это не реализовано, но можно поставить по нулям значения BUFFER_SIZE, NUM_FILES и все файлы будут удаляться.

Алгоритм работы плеера:

Написав первую версию прокси я столкнулся с особенностями плеера. Не знаю с чем это связано, но проблемы возникают с большими flac файлами. Плеер не совсем рассчитан на такого рода файлы и поэтому имеет ещё баги в алгоритме их воспроизведения.

Типичное воспроизведение начинается с двух запросов. Почему не с одного для меня до сих пор загадка. Т.е. плеер запрашивает файл целиком, читает первые 50кб-100кб и сбрасывает подключение. Запрашивает файл целиком второй раз и начинает читать опять с начала файл. Далее запросы становятся с указанием начального байта.
Пробовал сделать двух поточную прокси и думал, что он пытается читать в двух потоках, но плеер упорно не хотел присылать два запроса одновременно. Только последовательно. Причём первое соединение он рвёт почти сразу.
Так вот это не все проблемы. По какой-то странной особенности после первой порции файла, плеер начинает читать конец файла. Выбирает какую-то точку перед концом и читает до конца. Например, последние 200кб. Видимо ищет какие-то данные, которые не нашёл в начале или проверяет, что-то. Затем продолжает читать сначала.
Проблемы с flac файлами — это низкая скорость прокси при перемотке и плохой алгоритм. При перемотке flac плеер ищет подходящее начало потока. Т.е. он не с любого байта может начать играть. Поэтому делает 1-6 запросов. Видимо в этот момент задействуются какие-то таймауты, что бы плеер работал быстро, поэтому я увеличил скорость работы сокетов таймаутом 1500ms… Без таймаута сокеты подолгу висят в бездействии и вместо 1-6 запросов происходит только 1-2. Что снижает вероятность того что плеер найдёт начало. А если плеер не находит начало, то выдаёт ошибку о не поддерживаемом формате. Таймаут полностью решает проблему зависания сокетов, но не решает проблему работы алгоритма плеера. Так как даже без прокси при перемотке flac файлов плеер периодически выдаёт ошибку «не поддерживаемый формат».

Читайте также:  Deer hunter african safari android планшет

Проверено — плеер делает одинаковое число запросов, как с прокси, так и без. С прокси запросы выполняются немного медленней. Примерно на 50-200мс… Из-за различных преобразований и открытия\закрытия сокетов, что было максимально уменьшено в последних версиях.

Алгоритм работы HTTP, FTP:

Именно процедура закрытия сокетов или потоков отнимает больше всего времени. Именно от этих процедур и можно отказаться в некоторых случаях для увеличения быстродействия.
С помощью FTP команды RETR происходит получение файла. Команда ABOR необходима для корректного прерывания передачи файла. Да, это правильно и хорошо. Только ведь некоторые FTP сервера могут работать сразу принимая новую команду. Т.е. без команды ABOR — сразу REST, RETR и уже получаем новый файл с указанного в REST байта. Отправка команды ABOR занимает около 100мс… Это ухудшает комфорт и скорость прокси. Для этого и создан «режим совместимости FTP». В этом режиме происходит отправка команды ABOR. Как я ни пытался автоматизировать выбор режима работы — не получилось. Поэтому сделал вручную. Без команды ABOR тоже должно работать. Просто будет происходить новая авторизация, вместо прерывания и может возникнуть проблема с сессиями. Необходимо смотреть лог FTP — если авторизация происходит почти каждый раз, то лучше включить режим.

Настройки FTP сервера:

Особо тестов было не много. Точно должно работать в пассивном режиме с открытом 21 портом для авторизации и 1000 портов (может меньше) для передачи данных. 1000 портов должно быть открыто на фаерволе и указано в фтп сервере. Число одновременных сессий 10. Таймаут сессии 10 минут. Таймаут подключения 1 минута.

Алгоритм работы HTTP прокси:

Цифрами обозначена последовательность действий.

Для FTP сервера последовательность будет немного другой. В прокси есть ещё алгоритмы перехода на чтение с локального файла, если недоступен интернет или нет ответа от сервера. Местами алгоритмы очень сложные. Я максимально старался создавать короткие конструкции. Думаю ещё можно что-то уменьшить.
Для реализации FTP протокола я использовал библиотеку Apache Commons Net. Она поддерживает и некоторые другие протоколы: FTPS,FTP over HTTP (experimental),NNTP,SMTP(S),POP3(S),IMAP(S),Telnet,TFTP,Finger,Whois,rexec/rcmd/rlogin,Time (rdate) and Daytime,Echo,Discard,NTP/SNTP.
Думаю на основе тех из них, которые поддерживают приём данных из удалённого сервера и старт с определённого байта можно сделать прокси для плеера и играть мультимедиа.

Алгоритм сохранения файла:

Нуждается в доработке, но даже сейчас работает прекрасно. Суть проста — если вы прослушали весь файл, то он переименовывается в оригинальное расширение и имя. Проверка осуществляется с точностью до байта в момент окончания чтения файла. Если переименовывать не расширение, а имя файла, то мультимедиа сканер устройства поймёт что это какое-то мультимедиа и начнёт его сканировать. И если вдруг файл окажется битым вы получите 100% загрузку процессора до перезагрузки устройства. Возможно в разных андроид системах что-то по разному, но у меня на 4.4.2 так.
Проблема сейчас в том что кэшируется только то, что запрашивает и читает плеер. Нужна организация какой-то докачки в то время, когда плеер ничего не читает, что бы не нагружать канал и прекращение её без задержки для запроса плеера. Пока не получается уловить момент, когда плеер ничего не читает из интернета.

Источник

Оцените статью