- mvsde / android-volume-steps.md
- This comment has been minimized.
- bickbick commented Feb 25, 2020
- This comment has been minimized.
- mvsde commented Feb 25, 2020
- This comment has been minimized.
- This comment has been minimized.
- simlu commented Apr 27, 2020
- This comment has been minimized.
- mvsde commented Apr 27, 2020
- This comment has been minimized.
- This comment has been minimized.
- mvsde commented Apr 27, 2020
- This comment has been minimized.
- simlu commented Apr 27, 2020
- This comment has been minimized.
- This comment has been minimized.
- lucidBrot commented Feb 15, 2021
- This comment has been minimized.
- bickbick commented Feb 23, 2021
- Хранение данных и файлов
- Внешняя карта памяти
- Состояние на текущий момент
- Что делать?
- Android 11
- Как отключить предупреждение о вреде долгого прослушивания аудио (Android)
- Почему оно возникает
- Реализация
- Как отключить предупреждение
- Как отключить предупреждение без root
- Итоги
mvsde / android-volume-steps.md
Android Volume Steps
Connect through ADB
- Boot into TWRP
- Connect device to computer
- Terminal: List devices with adb devices
- TWRP: Mount > System
Get and edit props file
- Editor: Add the following settings to the pulled file
Push props file
- Terminal: Push file back to the device
- Terminal: Adjust permissions of the pushed file
This comment has been minimized.
Copy link Quote reply
bickbick commented Feb 25, 2020
For Android 10, build.prop is default.prop
This comment has been minimized.
Copy link Quote reply
mvsde commented Feb 25, 2020
Thanks for the note. I didn’t have to do this in a long time. Totally forgot about this Gist 🙈
This comment has been minimized.
Copy link Quote reply
This comment has been minimized.
Copy link Quote reply
simlu commented Apr 27, 2020
Does this work for pixel devices?
This comment has been minimized.
Copy link Quote reply
mvsde commented Apr 27, 2020
I have no idea. I used this successfully with LineageOS. This article on XDA sounds like it works on Pixel devices too: https://www.xda-developers.com/google-pixel-2-25-media-volume-steps/
The only way to find out is to try it, I guess 😁
This comment has been minimized.
Copy link Quote reply
This comment has been minimized.
Copy link Quote reply
mvsde commented Apr 27, 2020
Thank you @bickbick for the clarification 👍
This comment has been minimized.
Copy link Quote reply
simlu commented Apr 27, 2020
@bickbick On a Pixel 3 with latest Android only /system/build.prop seems to be present. The /system/default.prop file is not present.
This comment has been minimized.
Copy link Quote reply
This comment has been minimized.
Copy link Quote reply
lucidBrot commented Feb 15, 2021
Thanks for the guide! I ended up instead using the Magisk Hide Props Config Module because I already had that anyway. Made it easy to just run props at boot and set the custom values. However, it’s creator points out that ro.debuggable can sometimes trigger safetyNet here. Thought that’d be a good addition to this thread.
Sensitive props
Some apps trigger if they find «sensitive props». Also, on some devices SafetyNet triggers if certain props are not set to the expected values. A few props are set to «safe» values by MagiskHide by default. These prop are known to trigger some apps that look for root and «tampered» devices. Currently these are (apart from props for the bootloader state):
This comment has been minimized.
Copy link Quote reply
bickbick commented Feb 23, 2021
OK, thanks for more info on this subject.
I’ve got a Samsung A71 now and can’t mod the .prop file. sigh. But PowerAmp media player has a way to extend the volume steps without rooting the phone. (I would like to root the phone though, maybe when it’s out of warranty!).
Источник
Хранение данных и файлов
В целом хранение файлов и данных можно условно разделить на две группы: во внутреннем или внешнем хранилище. Но разница между ними довольна тонка. В целом политика Гугла в отношение данных ужесточается с каждой версии системы.
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.» – то есть это просто кусок внутренней памяти, которая путём какой-то эмуляции делается доступной для пользователя, в отличие от собственно внутренней памяти.
При этом с точки зрения системы доступная для пользователя папка называется /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» для приложений, которые ещё используют старую модель доступа к файлам.
Как временное решение можно добавить в блок манифеста application атрибут android:requestLegacyExternalStorage=»true», чтобы доступ к файлам был как раньше в Android 4.4-9.0.
Android 11
Если вы создаёте файловый менеджер, то ему нужны возможности для просмотра файлов. Для этого следует установить разрешение MANAGE_EXTERNAL_STORAGE или использовать атрибут android:requestLegacyExternalStorage=»true» (см. выше).
Источник
Как отключить предупреждение о вреде долгого прослушивания аудио (Android)
Наверное, многие, кто слушает музыку (и не только) с Android-устройства, сталкивались с таким предупреждением:
В этой статье мы рассмотрим, почему и когда возникает данное предупреждение, и как сделать так, чтобы оно больше не возникало.
Появляется оно только при прослушивании аудио через внешнее устройство (наушники/колонки). Для тех, кто не встречался с таким, небольшое пояснение: представьте, что вы слушаете музыку в наушниках, довольно громкую. Внезапно звук становится тише. Вы пытаетесь прибавить громкость, используя кнопки на корпусе, но не выходит. Достав устройство из кармана и сняв блокировку, вы и увидите такое предупреждение. Только после согласия с ним можно будет прибавить громкость обратно.
Да, предупреждение разумное, но появляется оно в непредсказуемый момент, иногда самый неподходящий: когда вы в общественном транспорте/за рулём/зимой на улице/когда у вас грязные руки и т.д. Доставать устройство, снимать блокировку, соглашаться с предупреждением, класть устройство обратно в этих случаях неудобно. А в случае, если подключены колонки, а не наушники, сообщение не совсем уместно.
Почему оно возникает
Данное предупреждение — не собственная инициатива авторов платформы. Всё дело в том, что существует WHO-ETU стандарт “безопасного прослушивания” (safe listening). В европейских и некоторых других странах его выполнение обязательно. В стандарте описывается, как долго можно прослушивать аудио в зависимости от громкости с минимальным риском снижения слуха. Например, для взрослого человека безопасная недельная “доза” звука — 1.6 Pa 2 h, что эквивалентно 20 часам прослушивания на громкости 83 dB.
Реализация
В зависимости от mcc (mobile country code), режим safe listening может быть включен или выключен. Определяется это значением ресурса R.bool.config_safe_media_volume_enabled .
Если режим включен, то система считает время прослушивания на небезопасной громкости (выше 85 dB), и периодически сохраняет значение в переменную Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS . Когда значение достигает 20 часов, выводится предупреждение. После согласия с предупреждением значение сбрасывается, и подсчёт начинается заново.
Такая реализация довольно простая и не учитывает, например, в течение какого времени пользователь прослушал эти 20 часов: возможно, за пару дней, а, может, слушал по 6-7 минут в течение полугода (в соответствии со стандартом это не является угрозой для слуха).
Логика safe listening сосредоточена в классе классе AudioService.java, в нём можно увидеть соответствующие поля:
Поле mMusicActiveMs содержит число миллисекунд, прослушанных пользователем на небезопасной громкости со времени последнего подтверждения диалога. Начальное значение загружается из переменной Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS . В эту же переменную каждую минуту записывается новое значение mMusicActiveMs.
Также есть поле mSafeMediaVolumeState , оно содержит текущее состояние системы safe listening:
- DISABLED : отключена
- ACTIVE : включена, и при этом лимит прослушивания достигнут, а значит нельзя разрешать пользователю увеличивать громкость, пока он не согласится с предупреждением
- INACTIVE : включена, лимит пока не достигнут
Метод проверки превышения лимита выглядит так:
Как отключить предупреждение
Чтобы выключить safe listening, нужно добиться того, чтобы переменной mSafeMediaVolumeState на этапе конфигурации было присвоено значение DISABLED .
Посмотрим, где изначально задаётся значение:
Видим, что помимо значения ресурса R.bool.config_safe_media_volume_enabled , есть два свойства, позволяющих включать/выключать систему safe listening: audio.safemedia.force и audio.safemedia.bypass.
Чтобы отключить предупреждение, нужно установить значение audio.safemedia.bypass=true в файле system/build.properties. Но для этого нужны root-права. Если их нет, то нужно разбираться дальше и искать другой способ.
Как отключить предупреждение без root
Давайте посмотрим, что происходит при закрытии диалога с предупреждением по нажатию ОК, и попробуем это воспроизвести:
Вызывается метод disableSafeMediaVolume у инстанса AudioManager .
Он помечен аннотацией @hide . Это означает, что метод не будет включён в public API несмотря на модификатор public. До Android 9 это легко можно было обойти используя рефлекшн. Теперь же такой метод по-прежнему можно вызывать, но уже с помощью трюка под названием double-reflection:
Вызов заканчивается исключением
java.lang.SecurityException: Only SystemUI can disable the safe media volume: Neither user 10307 nor current process has android.permission.STATUS_BAR_SERVICE.
Разрешение STATUS_BAR_SERVICE имеет protectionLevel=«signature|privileged», получить его не получится.
Что ж, тогда попробуем так. Мы будем следить за переменной Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS , в которую периодически сохраняется текущее значение mMusicActiveMs . Когда значение начнёт приближаться к 20 часам, будем его сбрасывать. Затем нужно будет сделать так, чтобы AudioService прочитал новое значение из настроек.
Прочитать значение Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS можно так:
То же самое, используя adb:
А чтобы записать значение, приложению потребуется разрешение android.permission.WRITE_SECURE_SETTINGS .
Оно имеет protectionLevel=«signature|privileged|development», а значит его можно выдать приложению используя adb:
Само значение записать можно так:
То же самое можно сделать с помощью adb:
Сбрасывать лучше в 1, как это сделано в AudioManager, а не в 0. Так как 0 соответствует состоянию ACTIVE.
Теперь нужно, чтобы AudioService прочитал новое значение, и обновил значение локальной переменной mMusicActiveMs .
Есть подходящий метод в AudioManager.java
Он инициирует вызов метода readAudioSettings в AudioService , где происходит загрузка mMusicActiveMs из настроек.
Метод помечен аннотацией @hide . Его вызов с помощью double-reflection вызывает исключение:
java.lang.SecurityException: Permission Denial: get/set setting for user asks to run as user -2 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL
Да, аннотация @hide здесь тоже неспроста. Получить данное разрешение мы, конечно не можем. Оно имеет protectionLevel=«signature|installer».
Остаётся один способ заставить AudioService прочитать новое значение — его перезапуск. Просто так перезапустить системный сервис нельзя. Нужно или перезагрузить устройство, или переключиться на другого пользователя, а затем вернуться обратно.
Теперь настало время проверить теорию.
Устанавливаем unsafe_volume_music_active_ms = 71 990 000 (останется 10 секунд, в течение которых можно прослушивать музыку на высокой громкости)
Перезапускаем устройство (можно вместо этого переключиться на другого пользователя, а потом вернуться):
Подключаем наушники, включаем музыку погромче. В течение минуты появляется диалог.
Теперь повторяем те же действия, но присваиваем unsafe_volume_music_active_ms = 1. Включаем музыку, ждём минуту. Диалог не появляется.
Итоги
Чтобы отключить предупреждение, можно сделать следующее:
При наличии root-прав
Установить значение audio.safemedia.bypass=true в файле system/build.properties
Нужно следить за значением Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS , и не давать ему подниматься выше 72 000 000 (20 часов). После сброса значения нужно перезапускать устройство (или переключаться на другого пользователя, а затем возвращаться обратно).
Я написала код простого приложения, которое делает эту работу, и напоминает о необходимости перезагрузить устройство/перелогиниться.
Источник