Compare commits

..
Author SHA1 Message Date
aliveoutside a4a5eb5638 init feat 2023-03-27 18:03:08 +03:00
1248 changed files with 37027 additions and 49807 deletions
+49 -57
View File
@@ -1,22 +1,49 @@
### Весь функционал модификации ### Все функции модификации
# Реклама * Лента
* Блокировка рекламы в ленте + * Блокировка рекламы в ленте
* Блокировка историй с возможной рекламой + * Блокировка постов через фильтры
* Блокировка постов: * Возможность добавлять в вайтлист фильтров группы, чтобы в них не удалялись посты
* С источником
* С MiniApp
* Через фильтры групп, слов
* Возможность добавлять в вайтлист фильтров группы, чтобы в них не удалялись посты+
* Возможность отключить рекомендации от ВК * Возможность отключить рекомендации от ВК
* Отключение отправки метрики * Медиаконтент
# Интерфейс и внешний вид
* Округление дат * Округление дат
* 1 января в 4:20 * 1 января в 4:20
* 1 января в 4:20:00 * 1 января в 4:20:00
* 1 января 2000 в 4:20:00 * 1 января 2000 в 4:20:00
* Округление чисел * Округление чисел
* Сокращение постов **(Показать полностью)**
* Результаты опросов без участия
* Возможность указывать папку для загрузки фото/видео/музыки/всего
* Интеграция с <a href="https://www.last.fm/">LAST.FM</a> (а также возможность скробблинга)
* Возможность **кешировать музыку / автокешировать ее при прослушивании**
* Возможность выбирать раздел музыки, открываемый по умолчанию
* Возможность скачивать видео, очищать историю просмотра видео
* Возможность найти фотографию через поисковые системы
* Интеграция с <a href="https://vkx.app/">VK X</a>
* Возможность кешировать треки в приложении
* Сообщения
* Обои в сообщениях
* Возможность выключения кнопки записи голосовых сообщений
* Возможность скрыть блок рекомендаций в сообщениях
* Режим **VK Me**
* Возможность вернуть вкладку уведомлений для режима VK Me
* Встроенный переводчик текста для сообщений
* Возможность выбрать язык перевода
* Автоматический перевод ваших сообщений на выбранный язык
* Альтернативный дизайн эмодзи меню
* Возможность использовать системные эмодзи
* Возможнсть использовать Enter с аппаратной клавиатуры
* Панель ввода из приложения VK для iOS
* Telegram Стикеры
* Возможность загружать свои стикерпаки из Telegram во ВКонтакте
* Внешний вид
* Возможность отключать новый дизайн версий VK (Milkshake)
* Название заголовков в докбаре
* Возможность использовать акцент для иконок
* Возможность отключить счётчики в докбаре
* Смена иконки приложения (содержит много уникальных иконок для донатеров)
* Возможность покрасить панель навигации, веб-страницы
* Интерфейс
* Возможность отключить блок историй наверху ленты * Возможность отключить блок историй наверху ленты
* Возможность отключить боковую камеру в разделе «Новости» * Возможность отключить боковую камеру в разделе «Новости»
* Возможность отключить блок «Что у вас нового?» в разделе «Новости» * Возможность отключить блок «Что у вас нового?» в разделе «Новости»
@@ -29,58 +56,23 @@
* Возможность отключить сокращение названий разделов в меню * Возможность отключить сокращение названий разделов в меню
* Возможность скрыть блок рекомендаций друзей в разделе «Друзья» * Возможность скрыть блок рекомендаций друзей в разделе «Друзья»
* Возможность скрыть подписи в настройках * Возможность скрыть подписи в настройках
* Анимированный экран входа для Android 12+ * Редактор докбара
* Редактор докбара * Редактор элементов Superapp
* Редактор элементов Superapp * Активность
* Возможность отключать новый дизайн версий VK (Milkshake)
* Название заголовков в докбаре
* Возможность использовать свой акцент для иконок
* Возможность отключить счётчики в докбаре
* Смена иконки приложения (содержит много уникальных иконок для донатеров)
* Возможность покрасить панель навигации, веб-страницы
* Обои в сообщениях
* Возможность выключения кнопки записи голосовых сообщений
* Возможность скрыть блок рекомендаций в сообщениях
* Режим **VK Me**
* Возможность вернуть вкладку уведомлений для режима VK Me
* Встроенный переводчик текста для сообщений
* Альтернативный дизайн эмодзи меню
* Возможность использовать системные эмодзи
* Панель ввода из приложения VK для iOS
* Сокращение постов **(Показать полностью)**
* Результаты опросов без участия
# Медиаконтент
* Интеграция с <a href="https://www.last.fm/">LAST.FM</a> (а также возможность скробблинга)
* Возможность **кешировать музыку / автокешировать ее при прослушивании**
* Возможность выбирать раздел музыки, открываемый по умолчанию
* Возможность скачивать видео, очищать историю просмотра видео
* Возможность найти фотографию через поисковые системы ?
* Интеграция с <a href="https://vkx.app/">VK X</a>
* Поддержка новых текстов в музыке (и с Genius в том числе)
# Сообщения
* Шифрование сообщений
* Возможность видеть удаленные сообщения * Возможность видеть удаленные сообщения
* Нечиталка/неписалка для ЛС/бесед/ботов/групп
* Возможность загружать свои стикерпаки из Telegram во ВКонтакте
* Возможнсть использовать Enter с аппаратной клавиатуры
# Активность
* Возможность сохранять удалённые сообщения
* Функционал, позволяющий оставаться в «оффлайне» (принудительный оффлайн/не отправлять статус онлайна и т.п.) * Функционал, позволяющий оставаться в «оффлайне» (принудительный оффлайн/не отправлять статус онлайна и т.п.)
* Нечиталка/неписалка для ЛС/бесед/ботов/групп
* Возможность отключить информацию о том, что вы просмотрели историю/прослушали голосовое сообщение * Возможность отключить информацию о том, что вы просмотрели историю/прослушали голосовое сообщение
* Возможность видеть онлайн пользователей, если у вас скрыт онлайн через VK Messenger * Возможность видеть онлайн пользователей, если у вас скрыт онлайн через VK Messenger
* Возможность сохранять настройки бесшумных сообщений/сообщений-бомбочек * Возможность сохранять настройки бесшумных сообщений/сообщений-бомбочек
* Отключить уведомление о том, что вы сделали скриншот в беседе * Отключить уведомление о том, что вы сделали скриншот в беседе
* Отключение редиректа через away.php * Отключение редиректа через away.php
* Отключение бизнес-уведомлений * Отключение отправки метрики
* Прокси
# Прокси
* Поддержка сторонних прокси, таких как: Zaborona, VikaMobile, рандомные прокси и прочие * Поддержка сторонних прокси, таких как: Zaborona, VikaMobile, рандомные прокси и прочие
* Возможность использовать **HTTP/HTTPS/SOCKS** прокси, менять домены **API/OAuth/Static** * Возможность использовать **HTTP/HTTPS/SOCKS** прокси, менять домены **API/OAuth/Static**
* Другое
# Другое * Синхронизация контактов с VK
* Очистка кеша приложения (**всё/стикеры/изображения/видео/сообщения/WebView**)
* Автоочистка кеша при достижении указанного вами значения (**100/500 MB, 1/2/5 GB**) * Автоочистка кеша при достижении указанного вами значения (**100/500 MB, 1/2/5 GB**)
* Возможность создания резервной копии (бекапа) настроек и аккаунтов * Функционал для **дебага приложения/бэкап возможности/верификации VTosters**
+4 -13
View File
@@ -21,21 +21,14 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Set up JDK 14
uses: actions/checkout@v3
- name: Set up NDK
uses: nttld/setup-ndk@v1
with:
ndk-version: r25c
add-to-path: false
- name: Set up JDK
uses: actions/setup-java@v3 uses: actions/setup-java@v3
with: with:
java-version: '17' java-version: '14'
distribution: 'adopt' distribution: 'adopt'
- uses: actions/checkout@v3
- name: Download tools - name: Download tools
run: | run: |
sudo apt update sudo apt update
@@ -54,8 +47,6 @@ jobs:
java -jar scripts/apktool.jar b smali -o smali/VTLite.apk --use-aapt2 -p scripts/framework/ java -jar scripts/apktool.jar b smali -o smali/VTLite.apk --use-aapt2 -p scripts/framework/
zipalign -p -f 4 smali/VTLite.apk smali/VTLite.apk_aligned zipalign -p -f 4 smali/VTLite.apk smali/VTLite.apk_aligned
mv smali/VTLite.apk_aligned smali/VTLite.apk mv smali/VTLite.apk_aligned smali/VTLite.apk
env:
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
- name: Sign and verify the apk - name: Sign and verify the apk
run: | run: |
-28
View File
@@ -1,28 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="RClass Regeneration" type="ShConfigurationType">
<option name="SCRIPT_TEXT" value="" />
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/scripts/rclass_regenerator.sh" />
<option name="SCRIPT_OPTIONS" value="" />
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
<option name="INTERPRETER_PATH" value="/bin/zsh" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="EXECUTE_IN_TERMINAL" value="true" />
<option name="EXECUTE_SCRIPT_FILE" value="true" />
<envs />
<method v="2" />
</configuration>
<configuration default="false" name="RClass Regeneration" type="BatchConfigurationType" factoryName="Batch">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="PARENT_ENVS" value="true" />
<module name="" />
<option name="SCRIPT_NAME" value="./scripts/rclass_regenerator.bat" />
<option name="PARAMETERS" value="" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
-17
View File
@@ -1,17 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Update APKs Jars (MacOS)" type="ShConfigurationType">
<option name="SCRIPT_TEXT" value="" />
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/scripts/update_jars_brew.sh" />
<option name="SCRIPT_OPTIONS" value="" />
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
<option name="INTERPRETER_PATH" value="/bin/zsh" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="EXECUTE_IN_TERMINAL" value="true" />
<option name="EXECUTE_SCRIPT_FILE" value="true" />
<envs />
<method v="2" />
</configuration>
</component>
-17
View File
@@ -1,17 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Update APKs Jars" type="ShConfigurationType">
<option name="SCRIPT_TEXT" value="" />
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/scripts/update_jars.sh" />
<option name="SCRIPT_OPTIONS" value="" />
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
<option name="INTERPRETER_PATH" value="/bin/zsh" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="EXECUTE_IN_TERMINAL" value="true" />
<option name="EXECUTE_SCRIPT_FILE" value="true" />
<envs />
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="lite [app:buildAndInstallVTLBeta]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="app:buildAndInstallVTLBeta" />
</list>
</option>
<option name="vmOptions" value="-Xms4g -Xmx4g" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="lite [app:buildAndInstallVTLDev]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="app:buildAndInstallVTLDev" />
</list>
</option>
<option name="vmOptions" value="-Xms4g -Xmx4g" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="lite [app:buildAndInstallVTLRelease]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="app:buildAndInstallVTLRelease" />
</list>
</option>
<option name="vmOptions" value="-Xms4g -Xmx4g" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="lite [app:buildAndLaunchVTLBeta]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="app:buildAndLaunchVTLBeta" />
</list>
</option>
<option name="vmOptions" value="-Xms4g -Xmx4g" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="lite [app:buildAndLaunchVTLDev]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="app:buildAndLaunchVTLDev" />
</list>
</option>
<option name="vmOptions" value="-Xms4g -Xmx4g" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="lite [app:buildAndLaunchVTLRelease]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="app:buildAndLaunchVTLRelease" />
</list>
</option>
<option name="vmOptions" value="-Xms4g -Xmx4g" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="lite [app:buildVTLBeta]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="app:buildVTLBeta" />
</list>
</option>
<option name="vmOptions" value="-Xms4g -Xmx4g" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="lite [app:buildVTLDev]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="app:buildVTLDev" />
</list>
</option>
<option name="vmOptions" value="-Xms4g -Xmx4g" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="lite [app:buildVTLRelease]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="app:buildVTLRelease" />
</list>
</option>
<option name="vmOptions" value="-Xms4g -Xmx4g" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="lite [app:exportDexBeta]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="app:exportDexBeta" />
</list>
</option>
<option name="vmOptions" value="-Xms4g -Xmx4g" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="lite [app:exportDexDev]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="app:exportDexDev" />
</list>
</option>
<option name="vmOptions" value="-Xms4g -Xmx4g" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="lite [app:exportDexRelease]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="app:exportDexRelease" />
</list>
</option>
<option name="vmOptions" value="-Xms4g -Xmx4g" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="lite [app:prepareDexForMergeDev]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="app:prepareDexForMergeDev" />
</list>
</option>
<option name="vmOptions" value="-Xms4g -Xmx4g" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="lite [app:prepareDexForMergeRelease]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="app:prepareDexForMergeRelease" />
</list>
</option>
<option name="vmOptions" value="-Xms4g -Xmx4g" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
+4 -13
View File
@@ -37,7 +37,7 @@
* Стабильные сборки находятся в [Releases](https://github.com/vtosters/lite/releases) * Стабильные сборки находятся в [Releases](https://github.com/vtosters/lite/releases)
Зеркало на нашем [<img src="https://gitea.com/assets/img/logo.svg" align="center" width="20" height="20"/> Git](https://git.maki.su/vtosters/lite) Зеркало на нашем [<img src="https://git.maki.su/assets/img/logo.svg" align="center" width="20" height="20"/> Git](https://git.maki.su/gdlbo/lite)
### Быстрая навигация ### Быстрая навигация
@@ -129,15 +129,6 @@
Для сборки необходимо вызвать одну из следующих gradle tasks: Для сборки необходимо вызвать одну из следующих gradle tasks:
+ `./gradlew buildVTL + <Build Type>` - соберет и подпишет APK + `./gradlew buildVTL` - соберет и подпишет APK
+ `./gradlew buildAndInstallVTL + <Build Type>` - соберет, подпишет и попытается установить через ADB + `./gradlew buildAndInstallVTL` - соберет, подпишет и попытается установить через ADB
+ `./gradlew buildAndLaunchVTL + <Build Type>` - соберет, подпишет, попытается установить через ADB и запустит на устройстве + [FOR DEVS] `./gradlew prepareDexForMerge` - соберет все необходимое для сборки в `smali/`
+ [FOR DEVS] `./gradlew prepareDexForMerge + <Build Type>` - соберет все необходимое для сборки в `smali/`
+ [FOR DEVS] `./gradlew exportDex + <Build Type>` - экспортирование дексов из собранного приложения для переноса в `smali/`
```
Build types:
Dev
Beta
Release
```
+73 -63
View File
@@ -1,6 +1,8 @@
import org.apache.tools.ant.taskdefs.condition.Os import org.apache.tools.ant.taskdefs.condition.Os
import java.util.zip.ZipEntry
import java.util.zip.ZipFile import java.util.zip.ZipFile
import java.util.zip.ZipInputStream
plugins { plugins {
id 'com.android.application' id 'com.android.application'
@@ -19,10 +21,6 @@ cargo {
def smaliFolder = projectDir.toPath().resolve("../smali").normalize() def smaliFolder = projectDir.toPath().resolve("../smali").normalize()
def scriptsFolder = projectDir.toPath().resolve("../scripts").normalize() def scriptsFolder = projectDir.toPath().resolve("../scripts").normalize()
//you can add own folders with decompiled smali code
def dexes = smaliFolder.toFile()
.listFiles({ f -> f.isDirectory() && f.name.startsWith("smali") } as FileFilter)
.size()
versionFile { versionFile {
file = projectDir.toPath().resolve("src/main/assets/version.properties").toFile() file = projectDir.toPath().resolve("src/main/assets/version.properties").toFile()
@@ -52,22 +50,15 @@ android {
} }
buildTypes { buildTypes {
release {
minifyEnabled true
buildConfigField 'String', 'APPCENTER_KEY', '""'
proguardFile 'proguard-rules.pro'
}
rc {
minifyEnabled true
buildConfigField 'String', 'APPCENTER_KEY', '""'
proguardFile 'proguard-rules.pro'
}
dev { dev {
minifyEnabled false initWith release
buildConfigField 'String', 'APPCENTER_KEY', '""' buildConfigField 'String', 'APPCENTER_KEY', '""'
} }
beta { beta {
minifyEnabled false initWith release
buildConfigField 'String', 'APPCENTER_KEY', '""'
}
release {
buildConfigField 'String', 'APPCENTER_KEY', '""' buildConfigField 'String', 'APPCENTER_KEY', '""'
} }
} }
@@ -79,96 +70,114 @@ android {
} }
namespace 'ru.vtosters.lite' namespace 'ru.vtosters.lite'
ndkVersion '25.2.9519653' ndkVersion '25.2.9519653'
buildFeatures {
aidl true
}
}
task testClasses {
doLast {
println 'This is a dummy testClasses task'
}
} }
dependencies { dependencies {
implementation 'com.microsoft.appcenter:appcenter-analytics:5.0.4' implementation "com.microsoft.appcenter:appcenter-analytics:5.0.0"
implementation 'com.microsoft.appcenter:appcenter-crashes:5.0.4' implementation "com.microsoft.appcenter:appcenter-crashes:5.0.0"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
implementation 'net.sourceforge.streamsupport:streamsupport-minifuture:1.7.4' implementation 'net.sourceforge.streamsupport:streamsupport-minifuture:1.7.4'
implementation 'com.google.guava:guava:32.0.0-android'
implementation 'com.mpatric:mp3agic:0.9.1'
implementation fileTree(dir: 'libs', include: ['*.aar']) implementation fileTree(dir: 'libs', include: ['*.aar'])
compileOnly fileTree(dir: 'libs', include: ['*.jar']) compileOnly fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.google.guava:guava:23.3-android'
} }
task generateBuildTasks() { task generateBuildTasks() {
android.applicationVariants.all { variant -> android.applicationVariants.all { variant ->
variant.outputs.each { output -> variant.outputs.each { output ->
def buildType = output.name.toString().capitalize() def buildType = output.name.toString().capitalize()
if (buildType == "Base") return def lowerBuildType = buildType.toLowerCase()
task "exportDex$buildType"() { task "exportDex$buildType"() {
dependsOn('assemble' + buildType) dependsOn('assemble' + buildType)
doLast { doLast {
try { try {
def suffix = buildType.toLowerCase() var z = ""
String apkPath = projectDir.getAbsolutePath() + "/build/outputs/apk/$suffix/app-$suffix" if (lowerBuildType != "debug") {
def apk = new File(apkPath + "-unsigned.apk") z = "-unsigned"
if (!apk.exists()) apk = new File(apkPath + ".apk") }
def zip = new ZipFile(apk)
def dexCounter = dexes File moduleDir = projectDir
zip.stream() ZipInputStream inputStream = new ZipInputStream(new FileInputStream(moduleDir.getAbsolutePath() + "/build/outputs/apk/$lowerBuildType/app-$lowerBuildType${z}.apk"))
.filter(entry -> entry.name.matches("^classes(?:(?=\\d)2|)\\.dex\$") || entry.name == "assets/version.properties") ZipFile file = new ZipFile(moduleDir.getAbsolutePath() + "/build/outputs/apk/$lowerBuildType/app-$lowerBuildType${z}.apk");
.forEach(entry -> { ZipEntry entry
String filename while ((entry = inputStream.nextEntry) != null) {
if (entry.name.matches("^classes(?:(?=\\d)2|)\\.dex\$")) filename = "classes${++dexCounter}.dex" if (entry.getName().equals("classes.dex")) {
else filename = "version.properties" print('classes.dex found!')
println("Exporting " + entry.name)
def tmpFile = new File(projectDir, filename) FileOutputStream outputStream = new FileOutputStream(new File(moduleDir.getAbsoluteFile(), "classes6.dex"))
try (def is = zip.getInputStream(entry); def fos = new FileOutputStream(tmpFile)) {
def buff = new byte[0x800] byte[] buffer = new byte[1024]
int len int len = 0
while ((len = is.read(buff)) > 0) fos.write(buff, 0, len) while ((len = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, len)
}
outputStream.close()
}
if (entry.getName().equals("classes2.dex")) {
print('\nclasses2.dex found!')
FileOutputStream outputStream = new FileOutputStream(new File(moduleDir.getAbsoluteFile(), "classes7.dex"))
byte[] buffer = new byte[1024]
int len = 0
while ((len = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, len)
}
outputStream.close()
}
}
for (ZipEntry e : Collections.list(file.entries())) {
if (e.getName().endsWith("assets/version.properties")) {
var is = file.getInputStream(e)
FileOutputStream outputStream = new FileOutputStream(new File(moduleDir.getAbsoluteFile(), "version.properties"))
byte[] buffer = new byte[1024]
int len = 0
while ((len = is.read(buffer)) > 0) {
outputStream.write(buffer, 0, len)
}
outputStream.close()
print('\nversion.properties found!')
}
} }
});
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace() e.printStackTrace()
} }
} }
} }
task "prepareDexForMerge$buildType"(type: Copy) { task "prepareDexForMerge$buildType"(type: Copy) {
dependsOn('exportDex' + buildType) dependsOn('exportDex' + buildType)
// Remove comment for native lib build // Remove comment for native lib build
//dependsOn('cargoBuild') dependsOn('cargoBuild')
into smaliFolder.toString() into smaliFolder.toString()
from(projectDir) { from(projectDir) {
into '../smali' include 'classes6.dex'
include "classes*.dex" include 'classes7.dex'
} }
from(projectDir) { from(projectDir) {
include 'version.properties' include 'version.properties'
into 'assets' into 'assets'
} }
from('../native-effects/target/aarch64-linux-android/release') { // Remove comment for native lib build
from('../native-effects/target/aarch64-linux-android/release'){
include 'libnative_effects.so' include 'libnative_effects.so'
into 'lib/arm64-v8a' into 'lib/arm64-v8a'
} }
from('../native-effects/target/armv7-linux-androideabi/release') { from('../native-effects/target/armv7-linux-androideabi/release'){
include 'libnative_effects.so' include 'libnative_effects.so'
into 'lib/armeabi-v7a' into 'lib/armeabi-v7a'
} }
doLast {
new File(projectDir, "classes6.dex").delete()
new File(projectDir, "classes7.dex").delete()
new File(projectDir, "version.properties").delete()
} }
task "cleanTemporaryFiles$buildType"(type: Delete)
{
delete fileTree(dir: projectDir, include: ["*.dex", "version.properties"])
delete fileTree(dir: smaliFolder, include: ['*.dex', "assets/version.properties"])
} }
task "buildVTL$buildType"(type: Exec) { task "buildVTL$buildType"(type: Exec) {
dependsOn('prepareDexForMerge' + buildType) dependsOn('prepareDexForMerge' + buildType)
workingDir(projectDir.parentFile) workingDir(projectDir.parentFile)
finalizedBy "cleanTemporaryFiles$buildType"
if (Os.isFamily("unix") || Os.isFamily("mac")) { if (Os.isFamily("unix") || Os.isFamily("mac")) {
commandLine 'bash', '-c', './scripts/build.sh' commandLine 'bash', '-c', './scripts/build.sh'
} else { } else {
@@ -196,6 +205,7 @@ task generateBuildTasks() {
} }
} }
task generateRjava(type: Exec) { task generateRjava(type: Exec) {
workingDir(projectDir.parentFile) workingDir(projectDir.parentFile)
if (Os.isFamily("unix") || Os.isFamily("mac")) if (Os.isFamily("unix") || Os.isFamily("mac"))
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-25
View File
@@ -19,28 +19,3 @@
## hide the original source file name. ## hide the original source file name.
##-renamesourcefileattribute SourceFile ##-renamesourcefileattribute SourceFile
#-keepclassmembers class fq #-keepclassmembers class fq
-assumenosideeffects class android.util.Log {
public static boolean isLoggable(java.lang.String, int);
public static int v(...);
public static int i(...);
public static int w(...);
public static int d(...);
public static int e(...);
}
-repackageclasses
-allowaccessmodification
-optimizations
-optimizationpasses 5
-keepattributes SourceFile, LineNumberTable
-keep,allowoptimization class ru.vtosters.hooks.**, ru.vtosters.sponsorpost.internal.Native, ru.vtosters.lite.utils.AndroidUtils, ru.vtosters.lite.utils.NetworkUtils, ru.vtosters.lite.utils.CrashReporter, ru.vtosters.lite.ui.activities.**, ru.vtosters.lite.services.**, ru.vtosters.lite.ui.fragments.**, ru.vtosters.lite.themes.**, ru.vtosters.lite.music.hook.**, ru.vtosters.lite.music.cache.injectors.**, ru.vtosters.lite.ui.wallpapers.NativeEffects, com.aefyr.tsg.g2.TelegramStickersService {
public <fields>;
public <methods>;
public <init>(...);
}
-keep class com.vtosters.lite.** { *; }
-keep class com.vk.** { *; }
-keep class bruhcollective.itaysonlab.libvkx.client.** { *; }
+4 -4
View File
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<application <application
android:allowBackup="true" android:allowBackup="true"
@@ -1,19 +1,20 @@
package bruhcollective.itaysonlab.libvkx.client; package bruhcollective.itaysonlab.libvkx.client;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
import static ru.vtosters.lite.utils.Preferences.isValidSignature;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.os.RemoteException; import android.os.RemoteException;
import bruhcollective.itaysonlab.libvkx.ILibVkxService;
import com.vk.dto.music.MusicTrack; import com.vk.dto.music.MusicTrack;
import com.vk.music.common.MusicPlaybackLaunchContext; import com.vk.music.common.MusicPlaybackLaunchContext;
import ru.vtosters.hooks.other.Preferences;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static ru.vtosters.hooks.other.Preferences.getBoolValue; import bruhcollective.itaysonlab.libvkx.ILibVkxService;
import static ru.vtosters.hooks.other.Preferences.isValidSignature;
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
public class LibVKXClient { public class LibVKXClient {
@SuppressLint("StaticFieldLeak") @SuppressLint("StaticFieldLeak")
@@ -34,7 +35,7 @@ public class LibVKXClient {
public static boolean isVkxInstalled() { public static boolean isVkxInstalled() {
try { try {
getGlobalContext().getPackageManager().getPackageInfo("ua.itaysonlab.vkx", 0); getGlobalContext().getPackageManager().getPackageInfo("ua.itaysonlab.vkx", 0);
return isValidSignature() && !Preferences.serverFeaturesDisable(); return isValidSignature();
} catch (Exception unused) { } catch (Exception unused) {
return false; return false;
} }
@@ -77,11 +78,15 @@ public class LibVKXClient {
} }
} }
public static void lambdaplay(List<MusicTrack> list, MusicTrack musicTrack, ILibVkxService iLibVkxService) { public static void lambdaplay(List<MusicTrack> list, MusicTrack musicTrack, ILibVkxService iLibVkxService){
lambdaplay(list, musicTrack, iLibVkxService, null); lambdaplay(list, musicTrack, iLibVkxService, null);
} }
public static String asId(MusicTrack musicTrack) { public static String asId(MusicTrack musicTrack) {
return musicTrack.y1(); String id = musicTrack.e + "_" + musicTrack.d;
if (musicTrack.O != null && !musicTrack.O.equals("")) {
id += "_" + musicTrack.O;
}
return id;
} }
} }
@@ -1,5 +1,7 @@
package bruhcollective.itaysonlab.libvkx.client; package bruhcollective.itaysonlab.libvkx.client;
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserId;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@@ -8,11 +10,10 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import bruhcollective.itaysonlab.libvkx.ILibVkxService;
import java.util.List; import java.util.List;
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserId; import bruhcollective.itaysonlab.libvkx.ILibVkxService;
public class LibVKXClientImpl { public class LibVKXClientImpl {
private ILibVkxService serviceInstance; private ILibVkxService serviceInstance;
@@ -5,21 +5,24 @@ import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Build;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.app.NotificationManagerCompat; import androidx.core.app.NotificationManagerCompat;
import com.aefyr.tsg.g2.stickersgrabber.TelegramStickersGrabber; import com.aefyr.tsg.g2.stickersgrabber.TelegramStickersGrabber;
import com.vtosters.lite.R; import com.vtosters.lite.R;
import ru.vtosters.lite.utils.AndroidUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import ru.vtosters.lite.utils.AndroidUtils;
/** /**
* Created by Aefyr on 20.05.2018. * Created by Aefyr on 20.05.2018.
*/ */
public class NotificationsHelper { public class NotificationsHelper {
// private static final int NOTIFICATION_ID_BASE = 3921337; // private static final int NOTIFICATION_ID_BASE = 3921337;
private static final String NOTIFICATION_CHANNEL_ID = "tgss_chan_v5"; private static final String NOTIFICATION_CHANNEL_ID = "tgss_chan_v5";
private static final int MAX_UPDATE_NOTIFICATIONS_PER_SECOND = 3; private static final int MAX_UPDATE_NOTIFICATIONS_PER_SECOND = 3;
private static final int MIN_TIME_BETWEEN_UPDATE_NOTIFICATIONS = 1000 / MAX_UPDATE_NOTIFICATIONS_PER_SECOND; private static final int MIN_TIME_BETWEEN_UPDATE_NOTIFICATIONS = 1000 / MAX_UPDATE_NOTIFICATIONS_PER_SECOND;
@@ -3,6 +3,7 @@ package com.aefyr.tsg.g2;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.util.Log; import android.util.Log;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@@ -36,8 +37,10 @@ public class TelegramStickersPack extends CustomStickersPack {
public HashMap<String, List<Integer>> emojis = new HashMap<>(); public HashMap<String, List<Integer>> emojis = new HashMap<>();
public TelegramStickersPack(String id) { public TelegramStickersPack(String id) {
this.id = this.title = id; final var idLowerCase = id.toLowerCase();
this.hash = id.hashCode(); this.id = idLowerCase;
this.hash = idLowerCase.hashCode();
title = id;
} }
public JSONObject encodeEmojis() throws JSONException { public JSONObject encodeEmojis() throws JSONException {
@@ -101,7 +104,7 @@ public class TelegramStickersPack extends CustomStickersPack {
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
return obj instanceof TelegramStickersPack && ((TelegramStickersPack) obj).id.equals(id); return obj instanceof TelegramStickersPack && ((TelegramStickersPack) obj).id.equalsIgnoreCase(id);
} }
@Override @Override
@@ -8,7 +8,6 @@ import android.util.Log;
import com.aefyr.tsg.g2.sql.TelegramStickersDbHelper; import com.aefyr.tsg.g2.sql.TelegramStickersDbHelper;
import com.aefyr.tsg.g2.stickersgrabber.TelegramStickersGrabber; import com.aefyr.tsg.g2.stickersgrabber.TelegramStickersGrabber;
import com.aefyr.tsg.g2.stickersgrabber.TelegramStickersPackInfo; import com.aefyr.tsg.g2.stickersgrabber.TelegramStickersPackInfo;
import ru.vtosters.lite.ui.fragments.VTSettings;
import ru.vtosters.lite.ui.fragments.tgstickers.StickersFragment; import ru.vtosters.lite.ui.fragments.tgstickers.StickersFragment;
import java.io.File; import java.io.File;
@@ -26,13 +25,19 @@ import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
public class TelegramStickersService { public class TelegramStickersService {
private static final String TAG = "TGStickersService"; private static final String TAG = "TGStickersService";
private static TelegramStickersService instance; private static TelegramStickersService instance;
private final Context c;
private final ArrayList<TelegramStickersPack> packs; private final ArrayList<TelegramStickersPack> packs;
private final ArrayList<TelegramStickersPack> activePacks; private final ArrayList<TelegramStickersPack> activePacks;
private final ArrayList<TelegramStickersPack> inactivePacks; private final ArrayList<TelegramStickersPack> inactivePacks;
private final ArrayList<StickersEventsListener> listeners; private final ArrayList<StickersEventsListener> listeners;
private final HashSet<String> currentlyDownloading; private final HashSet<String> currentlyDownloading;
private final Handler uiThreadHandler; private final Handler uiThreadHandler;
private final TelegramStickersGrabber grabber; private final TelegramStickersGrabber grabber;
private final TelegramStickersDbHelper dbHelper; private final TelegramStickersDbHelper dbHelper;
private final ArrayList<Runnable> queuedTasks; private final ArrayList<Runnable> queuedTasks;
private final ThreadPoolExecutor executor; private final ThreadPoolExecutor executor;
@@ -42,14 +47,16 @@ public class TelegramStickersService {
private TelegramStickersService(Context context) { private TelegramStickersService(Context context) {
instance = this; instance = this;
this.c = context.getApplicationContext();
listeners = new ArrayList<>(); listeners = new ArrayList<>();
currentlyDownloading = new HashSet<>(); currentlyDownloading = new HashSet<>();
uiThreadHandler = new Handler(Looper.getMainLooper()); uiThreadHandler = new Handler(Looper.getMainLooper());
grabber = new TelegramStickersGrabber(null); grabber = new TelegramStickersGrabber(null);
dbHelper = new TelegramStickersDbHelper(context); dbHelper = new TelegramStickersDbHelper(c);
queuedTasks = new ArrayList<>(); queuedTasks = new ArrayList<>();
executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2); executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
notificationsHelper = new NotificationsHelper(context); notificationsHelper = new NotificationsHelper(c);
packs = new ArrayList<>(); packs = new ArrayList<>();
activePacks = new ArrayList<>(); activePacks = new ArrayList<>();
@@ -62,11 +69,11 @@ public class TelegramStickersService {
return instance == null ? new TelegramStickersService(c) : instance; return instance == null ? new TelegramStickersService(c) : instance;
} }
private void updatePacks(boolean notify) { private void updatePacks(final boolean notify) {
packs.clear(); packs.clear();
dbHelper.getAllPacks(new TelegramStickersDbHelper.PacksLoadingListener() { dbHelper.getAllPacks(new TelegramStickersDbHelper.PacksLoadingListener() {
@Override @Override
public void onPackLoaded(TelegramStickersPack pack) { public void onPackLoaded(final TelegramStickersPack pack) {
runOnUiThread(() -> { runOnUiThread(() -> {
packs.add(pack); packs.add(pack);
@@ -95,6 +102,14 @@ public class TelegramStickersService {
}); });
} }
public void addStickersEventsListener(StickersEventsListener listener) {
listeners.add(listener);
}
public void removeStickersEventsListener(StickersEventsListener listener) {
listeners.remove(listener);
}
private void notifyPackAdded(TelegramStickersPack pack, int atIndex) { private void notifyPackAdded(TelegramStickersPack pack, int atIndex) {
getGlobalContext().sendBroadcast(new Intent(StickersFragment.ACTION_RELOAD)); getGlobalContext().sendBroadcast(new Intent(StickersFragment.ACTION_RELOAD));
if (listeners.isEmpty()) if (listeners.isEmpty())
@@ -137,7 +152,6 @@ public class TelegramStickersService {
private void notifyActivePacksListChanged() { private void notifyActivePacksListChanged() {
getGlobalContext().sendBroadcast(new Intent(StickersFragment.ACTION_RELOAD)); getGlobalContext().sendBroadcast(new Intent(StickersFragment.ACTION_RELOAD));
getGlobalContext().sendBroadcast(new Intent(VTSettings.ACTION_INVALIDATE_TGS_COUNT));
if (listeners.isEmpty()) if (listeners.isEmpty())
return; return;
@@ -172,16 +186,20 @@ public class TelegramStickersService {
return inactivePacks; return inactivePacks;
} }
public void requestPackDownload(String id, File packFolder) { public boolean isDoneLoading() {
return ready;
}
public boolean requestPackDownload(final String id, File packFolder) {
if (currentlyDownloading.contains(id)) { if (currentlyDownloading.contains(id)) {
Log.e(TAG, String.format("Got request to download pack %s which is already downloading", id)); Log.e(TAG, String.format("Got request to download pack %s which is already downloading", id));
return; return false;
} }
if (!ready) { if (!ready) {
File folder = packFolder; final File folder = packFolder;
queuedTasks.add(() -> requestPackDownload(id, folder)); queuedTasks.add(() -> requestPackDownload(id, folder));
return; return true;
} }
TelegramStickersPack pack = new TelegramStickersPack(id); TelegramStickersPack pack = new TelegramStickersPack(id);
@@ -201,17 +219,18 @@ public class TelegramStickersService {
notifyPackAdded(pack, packs.size() - 1); notifyPackAdded(pack, packs.size() - 1);
} }
TelegramStickersPack newPack = pack; final TelegramStickersPack newPack = pack;
boolean isUpdate = update; final boolean isUpdate = update;
currentlyDownloading.add(id); currentlyDownloading.add(id.toLowerCase());
notificationsHelper.packStartedDownloading(newPack); notificationsHelper.packStartedDownloading(newPack);
// try-catch block to handle possible timeout exception
try { grabber.enableProxy();
grabber.grabPack(id, packFolder, pack.version, new TelegramStickersGrabber.PackDownloadListener() { grabber.grabPack(id, packFolder, pack.version, new TelegramStickersGrabber.PackDownloadListener() {
@Override @Override
public void onPackDownloaded(TelegramStickersPackInfo packInfo, boolean newVersionFound) { public void onPackDownloaded(TelegramStickersPackInfo packInfo, boolean newVersionFound) {
runOnUiThread(() -> { runOnUiThread(() -> {
newPack.state = TelegramStickersPack.DOWNLOADED; newPack.state = TelegramStickersPack.DOWNLOADED;
notifyPackChanged(newPack, packs.indexOf(newPack)); notifyPackChanged(newPack, packs.indexOf(newPack));
@@ -230,7 +249,7 @@ public class TelegramStickersService {
} }
@Override @Override
public void onPackDownloadError(Exception e) { public void onPackDownloadError(final Exception e) {
runOnUiThread(() -> { runOnUiThread(() -> {
Log.e(TAG, "Error while downloading pack " + newPack.id); Log.e(TAG, "Error while downloading pack " + newPack.id);
e.printStackTrace(); e.printStackTrace();
@@ -251,7 +270,7 @@ public class TelegramStickersService {
} }
@Override @Override
public void onGotPackInfo(TelegramStickersPackInfo packInfo) { public void onGotPackInfo(final TelegramStickersPackInfo packInfo) {
runOnUiThread(() -> { runOnUiThread(() -> {
newPack.title = packInfo.title; newPack.title = packInfo.title;
newPack.stickersCount = packInfo.stickersCount; newPack.stickersCount = packInfo.stickersCount;
@@ -274,13 +293,11 @@ public class TelegramStickersService {
notificationsHelper.packDownloadUpdated(newPack, downloadedStickersCount); notificationsHelper.packDownloadUpdated(newPack, downloadedStickersCount);
} }
}); });
} catch (Exception e) {
// handle other possible exceptions return true;
e.printStackTrace();
}
} }
public void setPackEnabled(TelegramStickersPack pack, boolean enabled, boolean notify) { public void setPackEnabled(final TelegramStickersPack pack, final boolean enabled, final boolean notify) {
if (!ready) { if (!ready) {
queuedTasks.add(() -> setPackEnabled(pack, enabled, notify)); queuedTasks.add(() -> setPackEnabled(pack, enabled, notify));
return; return;
@@ -306,7 +323,7 @@ public class TelegramStickersService {
} }
} }
public void deletePack(TelegramStickersPack pack) { public void deletePack(final TelegramStickersPack pack) {
if (!ready) { if (!ready) {
queuedTasks.add(() -> deletePack(pack)); queuedTasks.add(() -> deletePack(pack));
return; return;
@@ -315,6 +332,7 @@ public class TelegramStickersService {
boolean d = dbHelper.deletePack(pack); boolean d = dbHelper.deletePack(pack);
Log.d(TAG, "Delete from DB=" + d); Log.d(TAG, "Delete from DB=" + d);
int index = packs.indexOf(pack); int index = packs.indexOf(pack);
packs.remove(index); packs.remove(index);
notifyPackRemoved(pack, index); notifyPackRemoved(pack, index);
@@ -335,7 +353,7 @@ public class TelegramStickersService {
uiThreadHandler.post(r); uiThreadHandler.post(r);
} }
private void syncPack(TelegramStickersPack pack) { private void syncPack(final TelegramStickersPack pack) {
if (!ready) { if (!ready) {
queuedTasks.add(() -> syncPack(pack)); queuedTasks.add(() -> syncPack(pack));
return; return;
@@ -377,4 +395,6 @@ public class TelegramStickersService {
void onInactivePacksListChanged(); void onInactivePacksListChanged();
} }
} }
@@ -8,7 +8,9 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.Log; import android.util.Log;
import com.aefyr.tsg.g2.TelegramStickersPack; import com.aefyr.tsg.g2.TelegramStickersPack;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@@ -5,42 +5,47 @@ import android.graphics.BitmapFactory;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.Log; import android.util.Log;
import com.aefyr.tsg.g2.stickersgrabber.util.Flag; import com.aefyr.tsg.g2.stickersgrabber.util.Flag;
import com.aefyr.tsg.g2.stickersgrabber.util.GoalCounter; import com.aefyr.tsg.g2.stickersgrabber.util.GoalCounter;
import okhttp3.*;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.Socket;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import ru.vtosters.lite.net.NetCall;
import ru.vtosters.lite.net.NetCallback;
import ru.vtosters.lite.net.NetClient;
import ru.vtosters.lite.net.NetRequest;
import ru.vtosters.lite.net.NetResponse;
/** /**
* Created by Aefyr on 11.05.2018. * Created by Aefyr on 11.05.2018.
*/ */
public class TelegramStickersGrabber { public class TelegramStickersGrabber {
private static final String TAG = "TSG"; private static final String TAG = "TSG";
private static final OkHttpClient sClient = VtOkHttpClient.getInstance(); public static String REAL_TG_IP = null;
private static final int MAX_RETRIES = 2; public static String PROXY_IP = null;
private static final AtomicInteger retryCount = new AtomicInteger(); public static int PROXY_PORT = -1;
private static final int STICKER_QUALITY = 100; public static String PROXY_USER = null;
private static final String STICKER_FILE_NAME_FORMAT = "%03d.png"; public static String PROXY_PASS = null;
private static final String STICKERS_KEY = "stickers"; public static boolean PROXY_SOCKS = true;
private static final String FILE_ID_KEY = "file_id"; public static boolean HAS_PASS = false;
private static final String EMOJI_KEY = "emoji"; public static boolean USE_PROXY = false;
private static final String IS_ANIMATED_KEY = "is_animated";
private static final String IS_VIDEO_KEY = "is_video";
private static final String THUMB_KEY = "thumb";
private static final String NAME_KEY = "name";
private static final String TITLE_KEY = "title";
private static String BOT_API_BASE_URL; private static String BOT_API_BASE_URL;
private static String GET_STICKER_SET_URL; private static String GET_STICKER_SET_URL;
private static String GET_FILE_URL; private static String GET_FILE_URL;
@@ -52,15 +57,17 @@ public class TelegramStickersGrabber {
private final MessageDigest sha256; private final MessageDigest sha256;
private final Handler uiThreadHandler; private final Handler uiThreadHandler;
private String botApiKey; private String botApiKey = "";
private NetClient httpClient;
public TelegramStickersGrabber(String botApiKey) { public TelegramStickersGrabber(String botApiKey) {
this.botApiKey = botApiKey; this.botApiKey = botApiKey;
httpClient = new NetClient.Builder().connectTimeout(5, TimeUnit.SECONDS).build();
uiThreadHandler = new Handler(Looper.getMainLooper()); uiThreadHandler = new Handler(Looper.getMainLooper());
try { try {
sha256 = MessageDigest.getInstance("SHA-256"); sha256 = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
Log.d(TAG, "No support for SHA-256"); Log.wtf(TAG, "No support for SHA-256");
e.printStackTrace(); e.printStackTrace();
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -69,12 +76,81 @@ public class TelegramStickersGrabber {
public static void updateURLs() { public static void updateURLs() {
BOT_API_BASE_FILE_URL = "https://api.telegram.org/file/bot%s/%s"; BOT_API_BASE_FILE_URL = "https://api.telegram.org/file/bot%s/%s";
BOT_API_BASE_URL = "https://api.telegram.org/bot%s/";
BOT_API_BASE_URL = REAL_TG_IP != null ? "https://" + REAL_TG_IP + "/bot%s/" : "https://api.telegram.org/bot%s/";
GET_STICKER_SET_URL = BOT_API_BASE_URL + "getStickerSet?name=%s"; GET_STICKER_SET_URL = BOT_API_BASE_URL + "getStickerSet?name=%s";
GET_FILE_URL = BOT_API_BASE_URL + "getFile?file_id=%s"; GET_FILE_URL = BOT_API_BASE_URL + "getFile?file_id=%s";
} }
public void grabPack(String id, File packFolder, String installedVersion, PackDownloadListener listener) { public static boolean isTelegramBlocked() {
NetClient client = new NetClient.Builder().connectTimeout(5, TimeUnit.SECONDS).build();
try {
if (PROXY_IP != null) {
Socket socket = new Socket(PROXY_IP, PROXY_PORT);
Proxy proxy = new Proxy(Proxy.Type.SOCKS, socket.getRemoteSocketAddress());
NetClient.Builder b = new NetClient.Builder().proxy(proxy);
if (PROXY_USER != null) {
b = b.proxyAuthenticator(new PasswordAuthentication(PROXY_USER, PROXY_PASS.toCharArray()));
}
client = b.build();
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
NetRequest req = new NetRequest.Builder().url(REAL_TG_IP != null ? "https://" + REAL_TG_IP + "/test/" : "https://api.telegram.org/test/").build();
try {
NetResponse res = client.newCall(req).execute();
String s = res.getDataString();
if (!s.equals("{\"ok\":false,\"error_code\":404,\"description\":\"Not Found\"}"))
return true;
} catch (Exception e) {
return true;
}
return false;
}
public void resetProxy() {
httpClient = new NetClient.Builder().connectTimeout(5, TimeUnit.SECONDS).build();
}
public void enableProxy() {
Thread kostil = new Thread() {
@Override
public void run() {
try {
if (PROXY_IP != null) {
Socket socket = new Socket(PROXY_IP, PROXY_PORT);
Proxy proxy = new Proxy(Proxy.Type.SOCKS, socket.getRemoteSocketAddress());
NetClient.Builder b = httpClient.newBuilder().proxy(proxy);
if (PROXY_USER != null) {
httpClient = b.proxyAuthenticator(new PasswordAuthentication(PROXY_USER, PROXY_PASS.toCharArray())).build();
}
httpClient = b.build();
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
kostil.start();
try {
kostil.join();
Log.d(TAG, "Proxy set");
} catch (InterruptedException e) {
Log.e(TAG, "Unable to set proxy:");
e.printStackTrace();
}
}
public void grabPack(String id, File packFolder, String installedVersion, final PackDownloadListener listener) {
getPackInfo(id, packFolder, installedVersion, listener); getPackInfo(id, packFolder, installedVersion, listener);
} }
@@ -82,207 +158,84 @@ public class TelegramStickersGrabber {
botApiKey = key; botApiKey = key;
} }
public void checkKey(KeyCheckListener listener) { public void checkKey(final KeyCheckListener listener) {
Log.d(TAG, "Checking key: " + botApiKey); Log.d(TAG, "Checking key: " + botApiKey);
// Create a request object with the URL and bot API key NetRequest request = new NetRequest.Builder().get().url(String.format(BOT_API_BASE_URL + "getMe", botApiKey)).build();
Request request = new Request.a() httpClient.newCall(request).enqueue(new NetCallback() {
.b(String.format(BOT_API_BASE_URL + "getMe", botApiKey))
.a();
// Create a new call object and enqueue it to run asynchronously
sClient.a(request).a(new Callback() {
@Override @Override
public void a(Call call, IOException e) { public void onFailure(NetCall call, IOException e) {
// Handle the failure case e.printStackTrace();
Log.d(TAG, e.getMessage());
runOnUiThread(listener::onNetError); runOnUiThread(listener::onNetError);
} }
@Override @Override
public void a(Call call, Response response) { public void onResponse(NetCall call, final NetResponse response) throws IOException {
Log.d(TAG, response.toString()); runOnUiThread(() -> listener.onKeyChecked(response.code() == 200));
runOnUiThread(() -> listener.onKeyChecked(response.h()));
} }
}); });
} }
private void getPack(StickerSet set, File packFolder, TelegramStickersPackInfo packInfo, PackDownloadListener listener) { private void getPackInfo(final String packName, final File packFolder, final String installedVersion, final PackDownloadListener listener) {
GoalCounter downloadedStickers = new GoalCounter(set.stickers.size(), () -> { NetRequest packInfoRequest = new NetRequest.Builder().get().url(String.format(GET_STICKER_SET_URL, botApiKey, packName)).build();
Log.d(TAG, String.format("Pack %s has been downloaded to %s", set.id, packFolder.getAbsolutePath())); httpClient.newCall(packInfoRequest).enqueue(new NetCallback() {
listener.onPackDownloaded(packInfo, true);
});
Flag deathFlag = new Flag();
for (int i = 0; i < set.stickers.size(); i++) {
Sticker sticker = set.stickers.get(i);
String getFileUrl = String.format(GET_FILE_URL, botApiKey, sticker.fileId);
Request fileInfoRequest = new Request.a()
.b(getFileUrl)
.a();
int stickerIndex = i + 1;
sClient.a(fileInfoRequest).a(new Callback() {
@Override @Override
public void a(Call call, IOException e) { public void onFailure(NetCall call, IOException e) {
handleFailure(deathFlag, listener, e, downloadedStickers, call, fileInfoRequest, this); listener.onPackDownloadError(e);
} }
@Override @Override
public void a(Call call, Response response) { public void onResponse(NetCall call, NetResponse response) {
if (deathFlag.up()) if (!response.isSuccessful()) {
return; if (response.getData() != null)
listener.onPackDownloadError(new TSGException(response.getDataString() + "\nURL: " + call.request().url()));
else
listener.onPackDownloadError(new TSGException("Unknown Exception, no response body"));
if (!response.h()) {
retryRequest(call, fileInfoRequest, this);
return; return;
} }
try (ResponseBody responseBody = response.a()) { StickerSet set;
JSONObject fileInfoResponse = new JSONObject(responseBody.g()).getJSONObject("result");
String filePath = fileInfoResponse.getString("file_path");
if (botApiKey == null) botApiKey = "";
String fileDownloadUrl = String.format(BOT_API_BASE_FILE_URL, botApiKey, filePath);
Request fileDownloadRequest = new Request.a()
.b(fileDownloadUrl)
.a();
sClient.a(fileDownloadRequest).a(new Callback() {
@Override
public void a(Call call, IOException e) {
handleFailure(deathFlag, listener, e, downloadedStickers, call, fileDownloadRequest, this);
}
@Override
public void a(Call call, Response response) {
if (deathFlag.up())
return;
if (!response.h()) {
retryRequest(call, fileDownloadRequest, this);
return;
}
try (ResponseBody responseBody = response.a()) {
if (responseBody == null) {
handleFailure(deathFlag, listener, new TSGException("Response body for a sticker is null :/"), downloadedStickers, call, fileDownloadRequest, this);
return;
}
InputStream stickerInputStream = responseBody.a();
Bitmap stickerImage = BitmapFactory.decodeStream(stickerInputStream);
if (stickerImage == null) {
handleFailure(deathFlag, listener, new TSGException("Unable to decode sticker image"), downloadedStickers, call, fileDownloadRequest, this);
return;
}
File stickerFile = new File(packFolder, String.format(STICKER_FILE_NAME_FORMAT, stickerIndex));
try { try {
saveStickerImage(stickerImage, stickerFile); JSONObject jPackInfo = new JSONObject(response.getDataString()).getJSONObject("result");
} catch (TSGException e) { String packVersion = new String(sha256.digest(jPackInfo.toString().getBytes(StandardCharsets.UTF_8)));
throw new RuntimeException(e);
}
listener.onStickerDownloaded(set.name, stickerFile, sticker.emoji, stickerIndex,
downloadedStickers.value() + 1, set.stickers.size());
downloadedStickers.increase();
}
}
});
} catch (Exception e) {
handleFailure(deathFlag, listener, e, downloadedStickers, call, fileInfoRequest, this);
}
}
});
}
}
private void handleFailure(Flag deathFlag, PackDownloadListener listener, Exception e, GoalCounter downloadedStickers, Call call, Request request, Callback callback) {
if ((e instanceof IOException || e instanceof TSGException) && retryCount.get() > MAX_RETRIES) {
Log.e(TAG, "Unable to download sticker: " + e.getMessage());
downloadedStickers.increase();
return;
} else if (retryCount.get() < MAX_RETRIES) {
retryRequest(call, request, callback);
return;
}
if (deathFlag.up()) {
return;
}
deathFlag.raise();
listener.onPackDownloadError(e);
}
private void retryRequest(Call call, Request request, Callback callback) {
retryCount.incrementAndGet();
if (retryCount.get() > MAX_RETRIES) {
Log.e(TAG, "retryRequest: max retries");
callback.a(call, new IOException());
} else {
Log.e(TAG, "retryRequest");
sClient.a(request).a(callback);
}
}
private void saveStickerImage(Bitmap image, File file) throws TSGException {
try (FileOutputStream fos = new FileOutputStream(file)) {
image.compress(Bitmap.CompressFormat.PNG, 100, fos);
} catch (IOException e) {
throw new TSGException("Unable to save sticker image");
}
}
private void getPackInfo(String packName, File packFolder, String installedVersion, PackDownloadListener listener) {
String getStickerSetUrl = String.format(GET_STICKER_SET_URL, botApiKey, packName);
Request packInfoRequest = new Request.a()
.b(getStickerSetUrl)
.a();
sClient.a(packInfoRequest).a(new Callback() {
@Override
public void a(Call call, IOException e) {
Log.d(TAG, e.getMessage());
listener.onPackDownloadError(e);
}
@Override
public void a(Call call, Response response) throws IOException {
Log.d(TAG, response.toString());
if (!response.h()) {
String errorMessage = response.a() != null ? response.a().g() + "\nURL: " + call.m0().g() : "Unknown Exception, no response body";
listener.onPackDownloadError(new TSGException(errorMessage));
return;
}
try (ResponseBody responseBody = response.a()) {
JSONObject packInfoResponse = new JSONObject(responseBody.g()).getJSONObject("result");
String packVersion = new String(sha256.digest(packInfoResponse.toString().getBytes(StandardCharsets.UTF_8)));
if (packVersion.equals(installedVersion)) { if (packVersion.equals(installedVersion)) {
listener.onPackDownloaded(null, false); listener.onPackDownloaded(null, false);
return; return;
} }
JSONArray stickersArray = packInfoResponse.getJSONArray(STICKERS_KEY); JSONArray jStickers = jPackInfo.getJSONArray("stickers");
if (stickersArray.length() == 0) { if (jStickers.length() == 0) {
listener.onPackDownloadError(new TSGException("No stickers in pack")); listener.onPackDownloadError(new TSGException("No stickers in pack"));
return; return;
} }
ArrayList<Sticker> stickers = parseStickers(stickersArray); ArrayList<Sticker> stickers = new ArrayList<>(jStickers.length());
StickerSet set = new StickerSet(packInfoResponse.getString(NAME_KEY), packInfoResponse.getString(TITLE_KEY), packVersion, stickers); Log.d(TAG, String.format("Parsing stickers in pack %s", packName));
for (int i = 0; i < jStickers.length(); i++) {
JSONObject jSticker = jStickers.getJSONObject(i);
if (jSticker.optBoolean("is_animated") || jSticker.optBoolean("is_video")) {
if (jSticker.has("thumb")) {
stickers.add(new Sticker(jSticker.getJSONObject("thumb").getString("file_id"), jSticker.getString("emoji")));
} else {
listener.onPackDownloadError(new TSGException("Animated and video stickerpacks without thumbs are not supported!"));
return;
}
} else {
stickers.add(new Sticker(jSticker.getString("file_id"), jSticker.getString("emoji")));
}
}
set = new StickerSet(jPackInfo.getString("name"), jPackInfo.getString("title"), packVersion, stickers);
} catch (Exception e) {
listener.onPackDownloadError(e);
return;
}
if (!packFolder.exists() && !packFolder.mkdirs()) { if (!packFolder.exists() && !packFolder.mkdirs()) {
// Handle the folder creation failure case
listener.onPackDownloadError(new IOException("Can't create folder for the pack!")); listener.onPackDownloadError(new IOException("Can't create folder for the pack!"));
return; return;
} }
@@ -290,39 +243,179 @@ public class TelegramStickersGrabber {
Log.d(TAG, String.format("Got info for pack %s, now downloading stickers to %s", packName, packFolder.getAbsolutePath())); Log.d(TAG, String.format("Got info for pack %s, now downloading stickers to %s", packName, packFolder.getAbsolutePath()));
TelegramStickersPackInfo packInfo = new TelegramStickersPackInfo(packName, set.name, set.stickers.size(), set.version); TelegramStickersPackInfo packInfo = new TelegramStickersPackInfo(packName, set.name, set.stickers.size(), set.version);
listener.onGotPackInfo(packInfo); listener.onGotPackInfo(packInfo);
getPack(set, packFolder, packInfo, listener); getPack(set, packFolder, packInfo, listener);
} catch (Exception e) {
listener.onPackDownloadError(e);
}
} }
}); });
} }
private ArrayList<Sticker> parseStickers(JSONArray stickersArray) throws JSONException, TSGException { private void getPack(final StickerSet set, final File packFolder, final TelegramStickersPackInfo packInfo, final PackDownloadListener listener) {
ArrayList<Sticker> stickers = new ArrayList<>(stickersArray.length()); final GoalCounter downloadedStickers = new GoalCounter(set.stickers.size(), () -> {
Log.d(TAG, String.format("Pack %s has been downloaded to %s", set.id, packFolder.getAbsolutePath()));
for (int i = 0; i < stickersArray.length(); i++) { listener.onPackDownloaded(packInfo, true);
JSONObject stickerObject = stickersArray.getJSONObject(i); });
boolean isAnimated = stickerObject.optBoolean(IS_ANIMATED_KEY); final Flag deathFlag = new Flag();
boolean isVideo = stickerObject.optBoolean(IS_VIDEO_KEY);
String fileId = stickerObject.getString(FILE_ID_KEY);
String emoji = stickerObject.getString(EMOJI_KEY);
if (isAnimated || isVideo) { AtomicInteger retryed = new AtomicInteger();
if (stickerObject.has(THUMB_KEY)) { for (int i = 0; i < set.stickers.size(); i++) {
fileId = stickerObject.getJSONObject(THUMB_KEY).getString(FILE_ID_KEY); final Sticker sticker = set.stickers.get(i);
} else { NetRequest fileInfoRequest = new NetRequest.Builder().get().url(String.format(GET_FILE_URL, botApiKey, sticker.fileId)).build();
throw new TSGException("Animated and video stickerpacks without thumbs are not supported!");
} final int stickerIndex = i + 1;
AtomicBoolean sync = new AtomicBoolean();
httpClient.newCall(fileInfoRequest).enqueue(new NetCallback() {
@Override
public void onFailure(NetCall call, IOException e) {
if (deathFlag.up())
return;
deathFlag.raise();
listener.onPackDownloadError(e);
sync.set(true);
} }
stickers.add(new Sticker(fileId, emoji)); @Override
public void onResponse(NetCall call, NetResponse response) throws IOException {
if (deathFlag.up())
return;
if (response.code() != 200) {
retryed.incrementAndGet();
if (retryed.get() > 5)
onFailure(call, new IOException());
else httpClient.newCall(fileInfoRequest)
.enqueue(this);
return;
} }
return stickers; String filePath;
try {
JSONObject jFileInfo = new JSONObject(response.getDataString()).getJSONObject("result");
filePath = jFileInfo.getString("file_path");
} catch (Exception e) {
deathFlag.raise();
listener.onPackDownloadError(e);
sync.set(true);
return;
}
if (botApiKey == null) botApiKey = "";
NetRequest fileDownloadRequest = new NetRequest.Builder().get().url(String.format(BOT_API_BASE_FILE_URL, botApiKey, filePath)).build();
httpClient.newCall(fileDownloadRequest).enqueue(new NetCallback() {
@Override
public void onFailure(NetCall call, IOException e) {
if (deathFlag.up())
return;
deathFlag.raise();
listener.onPackDownloadError(e);
sync.set(true);
}
@Override
public void onResponse(NetCall call, NetResponse response) throws IOException {
if (deathFlag.up())
return;
if (response.code() != 200) {
retryed.incrementAndGet();
if (retryed.get() > 5)
onFailure(call, new IOException());
else httpClient.newCall(fileDownloadRequest)
.enqueue(this);
return;
}
if (response.getData() == null) {
deathFlag.raise();
listener.onPackDownloadError(new TSGException("Response body for a sticker is null :/"));
sync.set(true);
return;
}
InputStream stickerInputStream = response.getDataStream();
Bitmap stickerImage = BitmapFactory.decodeStream(stickerInputStream);
try {
stickerInputStream.close();
} catch (IOException e) {
e.printStackTrace();
deathFlag.raise();
listener.onPackDownloadError(e);
sync.set(true);
return;
}
if (stickerImage == null) {
deathFlag.raise();
listener.onPackDownloadError(new TSGException("Unable to decode sticker image"));
sync.set(true);
return;
}
File stickerFile = new File(packFolder, String.format("%03d.png", stickerIndex));
FileOutputStream fileOutputStream;
try {
fileOutputStream = new FileOutputStream(stickerFile);
} catch (Exception e) {
e.printStackTrace();
deathFlag.raise();
listener.onPackDownloadError(e);
sync.set(true);
return;
}
if (!stickerImage.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)) {
stickerImage.recycle();
deathFlag.raise();
listener.onPackDownloadError(new TSGException("Unable to compress sticker to a png file at path: " + stickerFile.getAbsolutePath()));
sync.set(true);
return;
}
stickerImage.recycle();
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
deathFlag.raise();
listener.onPackDownloadError(e);
sync.set(true);
return;
}
listener.onStickerDownloaded(set.name, stickerFile, sticker.emoji, stickerIndex, downloadedStickers.value() + 1, set.stickers.size());
downloadedStickers.increase();
sync.set(true);
}
});
}
});
while (!sync.get())
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
}
}
} }
private void runOnUiThread(Runnable r) { private void runOnUiThread(Runnable r) {
@@ -345,13 +438,15 @@ public class TelegramStickersGrabber {
void onNetError(); void onNetError();
} }
public static class TSGException extends Exception { public class TSGException extends Exception {
private static final long serialVersionUID = 7866915509988422944L;
private TSGException(String message) { private TSGException(String message) {
super(message); super(message);
} }
} }
private static class StickerSet { private class StickerSet {
String id; String id;
String name; String name;
String version; String version;
@@ -365,7 +460,7 @@ public class TelegramStickersGrabber {
} }
} }
private static class Sticker { private class Sticker {
String emoji; String emoji;
String fileId; String fileId;
+125
View File
@@ -0,0 +1,125 @@
package com.arthenica.ffmpegkit;
import android.os.Build;
import android.util.Log;
import com.arthenica.smartexception.java.Exceptions;
import java.util.Collections;
import java.util.List;
public class NativeLoader {
static final String[] FFMPEG_LIBRARIES = {"avutil", "swresample", "avcodec", "avformat", "avfilter", "avdevice"};
private static void loadLibrary(String libraryName) {
System.loadLibrary(libraryName);
}
private static List<String> loadExternalLibraries() {
//return Packages.getExternalLibraries();
return Collections.emptyList();
}
private static String loadNativeAbi() {
return AbiDetect.getNativeAbi();
}
static String loadAbi() {
return AbiDetect.getAbi();
}
static String loadPackageName() {
return Packages.getPackageName();
}
static String loadVersion() {
return FFmpegKitConfig.getVersion();
}
static boolean loadIsLTSBuild() {
return AbiDetect.isNativeLTSBuild();
}
static int loadLogLevel() {
return FFmpegKitConfig.getNativeLogLevel();
}
static String loadBuildDate() {
return FFmpegKitConfig.getBuildDate();
}
static void enableRedirection() {
FFmpegKitConfig.enableRedirection();
}
static void loadFFmpegKitAbiDetect() {
loadLibrary("ffmpegkit_abidetect");
}
static boolean loadFFmpeg() {
boolean nativeFFmpegLoaded = false;
boolean nativeFFmpegTriedAndFailed = false;
if (AbiDetect.ARM_V7A.equals(loadNativeAbi())) {
try {
for (String ffmpegLibrary : FFMPEG_LIBRARIES) {
loadLibrary(ffmpegLibrary + "_neon");
}
nativeFFmpegLoaded = true;
} catch (final Error e) {
android.util.Log.i(FFmpegKitConfig.TAG, String.format("NEON supported armeabi-v7a ffmpeg library not found. Loading default armeabi-v7a library.%s", Exceptions.getStackTraceString(e)));
nativeFFmpegTriedAndFailed = true;
}
}
if (!nativeFFmpegLoaded) {
for (String ffmpegLibrary : FFMPEG_LIBRARIES) {
loadLibrary(ffmpegLibrary);
}
}
return nativeFFmpegTriedAndFailed;
}
static void loadFFmpegKit(boolean nativeFFmpegTriedAndFailed) {
boolean nativeFFmpegKitLoaded = false;
if (!nativeFFmpegTriedAndFailed && "arm-v7a".equals(loadNativeAbi())) {
try {
loadLibrary("ffmpegkit_armv7a_neon");
nativeFFmpegKitLoaded = true;
AbiDetect.setArmV7aNeonLoaded();
} catch (Error e) {
Log.i("ffmpeg-kit", String.format("NEON supported armeabi-v7a ffmpegkit library not found. Loading default armeabi-v7a library.%s", Exceptions.getStackTraceString(e)));
}
}
if (!nativeFFmpegKitLoaded) {
loadLibrary("ffmpegkit");
}
}
static String getDeviceDebugInformation() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("brand: ");
stringBuilder.append(Build.BRAND);
stringBuilder.append(", model: ");
stringBuilder.append(Build.MODEL);
stringBuilder.append(", device: ");
stringBuilder.append(Build.DEVICE);
stringBuilder.append(", api level: ");
stringBuilder.append(Build.VERSION.SDK_INT);
if (Build.VERSION.SDK_INT >= 21) {
stringBuilder.append(", abis: ");
stringBuilder.append(FFmpegKitConfig.argumentsToString(Build.SUPPORTED_ABIS));
stringBuilder.append(", 32bit abis: ");
stringBuilder.append(FFmpegKitConfig.argumentsToString(Build.SUPPORTED_32_BIT_ABIS));
stringBuilder.append(", 64bit abis: ");
stringBuilder.append(FFmpegKitConfig.argumentsToString(Build.SUPPORTED_64_BIT_ABIS));
} else {
stringBuilder.append(", cpu abis: ");
stringBuilder.append(Build.CPU_ABI);
stringBuilder.append(", cpu abi2s: ");
stringBuilder.append(Build.CPU_ABI2);
}
return stringBuilder.toString();
}
}
@@ -0,0 +1,732 @@
/*
* BSD 3-Clause License
*
* Copyright (c) 2020, Taner Sener
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.arthenica.smartexception;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* <p>Abstract class that includes common variables and methods for different <code>Exceptions</code> implementations.
*
* @author Taner Sener
* @since 0.1.0
*/
public abstract class AbstractExceptions {
/**
* <p>Default max depth used in methods which do not have a maxDepth argument.
*/
public static final int DEFAULT_MAX_DEPTH = 10;
/**
* <p>Default value for ignoring all causes when stack trace elements are printed or converted to string.
*/
public static final boolean DEFAULT_IGNORE_ALL_CAUSES = false;
/**
* <p>Stores global root package names.
*/
public static final Set<String> rootPackageSet = Collections.synchronizedSet(new HashSet<String>());
/**
* <p>Stores global group package names.
*/
public static final Set<String> groupPackageSet = Collections.synchronizedSet(new HashSet<String>());
/**
* <p>Stores global ignore package names.
*/
public static final Set<String> ignorePackageSet = Collections.synchronizedSet(new HashSet<String>());
/**
* <p>Stores global ignore cause package names.
*/
public static final Set<String> ignoreCausePackageSet = Collections.synchronizedSet(new HashSet<String>());
/**
* <p>Stores the value of global ignore all causes option.
*/
public static boolean ignoreAllCauses = DEFAULT_IGNORE_ALL_CAUSES;
/**
* <p>Stores the global stack trace serializer implementation.
*/
public static StackTraceElementSerializer stackTraceElementSerializer;
/**
* <p>Registers a new root package.
*
* @param packageString root package name to register
*/
public static void registerRootPackage(final String packageString) {
rootPackageSet.add(packageString);
}
/**
* <p>Clears previously registered root packages.
*/
public static void clearRootPackages() {
rootPackageSet.clear();
}
/**
* <p>Registers a new group package.
*
* @param packageString group package name to register
*/
public static void registerGroupPackage(final String packageString) {
groupPackageSet.add(packageString);
}
/**
* <p>Clears previously registered group packages.
*/
public static void clearGroupPackages() {
groupPackageSet.clear();
}
/**
* <p>Returns the global stack trace serializer implementation which is used to serialize {@link StackTraceElement}
* objects in <code>getStackTraceString</code> methods.
*
* @return current stack trace serializer implementation
*/
public static StackTraceElementSerializer getStackTraceElementSerializer() {
return stackTraceElementSerializer;
}
/**
* <p>Sets the global stack trace serializer implementation which is used to serialize {@link StackTraceElement}
* objects in <code>getStackTraceString</code> methods.
*
* @param stackTraceElementSerializer new stack trace serializer implementation
*/
public static void setStackTraceElementSerializer(final StackTraceElementSerializer stackTraceElementSerializer) {
AbstractExceptions.stackTraceElementSerializer = stackTraceElementSerializer;
}
/**
* <p>Registers a new ignore package.
*
* @param packageString ignore package name to register
* @param ignoreCauseClasses ignore cause classes from this package too
*/
public static void registerIgnorePackage(final String packageString, final boolean ignoreCauseClasses) {
ignorePackageSet.add(packageString);
if (ignoreCauseClasses) {
ignoreCausePackageSet.add(packageString);
}
}
/**
* <p>Clears previously registered ignore packages.
*/
public static void clearIgnorePackages() {
ignorePackageSet.clear();
ignoreCausePackageSet.clear();
}
/**
* <p>Returns the value of ignore all causes option.
*
* @return the value of global ignore all causes option. If value is true then stack trace elements printed or
* converted to string will not include causes. If value is false causes will be appended to the stack trace of
* the main throwable.
*/
public static boolean getIgnoreAllCauses() {
return ignoreAllCauses;
}
/**
* <p>Sets the value of ignore all causes option.
*
* @param ignoreAllCauses new global ignore all causes option. If value is true then stack trace elements printed
* or converted to string will not include causes. If value is false causes will be appended to the stack trace of
* the main throwable.
*/
public static void setIgnoreAllCauses(final boolean ignoreAllCauses) {
AbstractExceptions.ignoreAllCauses = ignoreAllCauses;
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code>.
*
* <p>This method uses root packages registered by {@link #registerRootPackage(String)}, group packages registered
* by {@link #registerGroupPackage(String)} and ignore packages registered by
* {@link #registerIgnorePackage(String, boolean)} to build the smart stack trace.
*
* @param throwable parent throwable
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable) {
return getStackTraceString(throwable, false, rootPackageSet, groupPackageSet, ignorePackageSet, 0, ignoreAllCauses);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code>.
*
* <p>This method uses root packages registered by {@link #registerRootPackage(String)}, group packages registered
* by {@link #registerGroupPackage(String)} and ignore packages registered by
* {@link #registerIgnorePackage(String, boolean)} to build the smart stack trace.
*
* @param throwable parent throwable
* @param ignoreAllCauses ignore all causes in the exception chain
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable, final boolean ignoreAllCauses) {
return getStackTraceString(throwable, false, rootPackageSet, groupPackageSet, ignorePackageSet, 0, ignoreAllCauses);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code> using packages provided.
*
* @param throwable parent throwable
* @param rootPackageSet root packages to use for building the stack trace
* @param groupPackageSet group packages to use for building the stack trace
* @param ignorePackageSet ignore packages to use for building the stack trace
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable, final Set<String> rootPackageSet, final Set<String> groupPackageSet, final Set<String> ignorePackageSet) {
return getStackTraceString(throwable, false, rootPackageSet, groupPackageSet, ignorePackageSet, 0, ignoreAllCauses);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code> using packages provided.
*
* @param throwable parent throwable
* @param rootPackageSet root packages to use for building the stack trace
* @param groupPackageSet group packages to use for building the stack trace
* @param ignorePackageSet ignore packages to use for building the stack trace
* @param ignoreAllCauses ignore all causes in the exception chain
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable, final Set<String> rootPackageSet, final Set<String> groupPackageSet, final Set<String> ignorePackageSet, final boolean ignoreAllCauses) {
return getStackTraceString(throwable, false, rootPackageSet, groupPackageSet, ignorePackageSet, 0, ignoreAllCauses);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code> using root package provided.
*
* @param throwable parent throwable
* @param rootPackage root package to use for building the stack trace
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable, final String rootPackage) {
return getStackTraceString(throwable, false, Collections.singleton(rootPackage), new HashSet<String>(), new HashSet<String>(), 0, ignoreAllCauses);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code> using root package provided.
*
* @param throwable parent throwable
* @param rootPackage root package to use for building the stack trace
* @param groupPackage group package to use for building the stack trace
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable, final String rootPackage, final String groupPackage) {
return getStackTraceString(throwable, false, Collections.singleton(rootPackage), Collections.singleton(groupPackage), new HashSet<String>(), 0, ignoreAllCauses);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code> using elements found until the maxDepth.
*
* @param throwable parent throwable
* @param maxDepth max depth in exception chain that will be used
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable, final int maxDepth) {
return getStackTraceString(throwable, false, new HashSet<String>(), new HashSet<String>(), new HashSet<String>(), maxDepth, ignoreAllCauses);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code> using elements found until the maxDepth.
*
* @param throwable parent throwable
* @param maxDepth max depth in exception chain that will be used
* @param ignoreAllCauses ignore all causes in the exception chain
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable, final int maxDepth, final boolean ignoreAllCauses) {
return getStackTraceString(throwable, false, new HashSet<String>(), new HashSet<String>(), new HashSet<String>(), maxDepth, ignoreAllCauses);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code> using parameters provided.
*
* @param throwable parent throwable
* @param isCause throwable is a cause or not
* @param rootPackageSet root packages to use for building the stack trace
* @param groupPackageSet group packages to use for building the stack trace
* @param ignorePackageSet ignore packages to use for building the stack trace
* @param maxDepth max depth in exception chain that will be used
* @param ignoreAllCauses ignore all causes in the exception chain
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable, final boolean isCause, final Set<String> rootPackageSet, final Set<String> groupPackageSet, final Set<String> ignorePackageSet, final int maxDepth, final boolean ignoreAllCauses) {
final StringBuilder builder = new StringBuilder();
if (throwable == null) {
return "";
}
final String className = throwable.getClass().getName();
final StackTraceElement[] stackTraceElements;
if (maxDepth > 0) {
stackTraceElements = getStackTrace(throwable, maxDepth);
} else {
stackTraceElements = getStackTrace(throwable, rootPackageSet, ignorePackageSet);
}
String message = throwable.getLocalizedMessage();
if (isEmpty(message)) {
message = throwable.getMessage();
}
/* PRINT MESSAGE */
if (isCause) {
builder.append(System.lineSeparator());
builder.append("Caused by: ");
builder.append(className);
if (!isEmpty(message)) {
builder.append(": ");
builder.append(message);
}
} else {
builder.append(System.lineSeparator());
builder.append(className);
if (!isEmpty(message)) {
builder.append(": ");
builder.append(message);
}
}
/* PRINT SHORT STACK TRACE */
String currentGroupPackage = null;
StackTraceElement firstStackTraceElementInTheGroup = null;
int currentGroupCount = 0;
for (StackTraceElement traceElement : stackTraceElements) {
String traceElementClassName = traceElement.getClassName();
String groupPackageMatch = getContainingPackage(traceElementClassName, groupPackageSet);
if (groupPackageMatch != null) {
if (!groupPackageMatch.equals(currentGroupPackage)) {
appendStackTraceGroupElement(builder, currentGroupPackage, currentGroupCount, firstStackTraceElementInTheGroup);
builder.append(System.lineSeparator());
builder.append("\tat ");
currentGroupPackage = groupPackageMatch;
firstStackTraceElementInTheGroup = traceElement;
currentGroupCount = 1;
} else {
currentGroupCount++;
}
} else {
currentGroupCount = appendStackTraceGroupElement(builder, currentGroupPackage, currentGroupCount, firstStackTraceElementInTheGroup);
builder.append(System.lineSeparator());
builder.append("\tat ");
if (stackTraceElementSerializer == null) {
throw new IllegalArgumentException("Stack trace element serializer not initialized.");
} else {
builder.append(stackTraceElementSerializer.toString(traceElement));
}
currentGroupPackage = null;
}
}
appendStackTraceGroupElement(builder, currentGroupPackage, currentGroupCount, firstStackTraceElementInTheGroup);
final Throwable cause = throwable.getCause();
if (cause != null && !containsPackage(className, ignoreCausePackageSet) && !ignoreAllCauses) {
builder.append(getStackTraceString(cause, true, rootPackageSet, groupPackageSet, ignorePackageSet, maxDepth, ignoreAllCauses));
}
return builder.toString();
}
/**
* <p>Appends stack trace group information for the given parameters.
*
* @param stringBuilder string builder that group stack trace information will be appended
* @param currentGroupPackage package name of the current group
* @param numberOfElementsInTheCurrentGroup number of elements in the current group
* @param firstStackTraceElementInTheGroup first stack trace element of this group
* @return new value for the group element count
*/
public static int appendStackTraceGroupElement(final StringBuilder stringBuilder, final String currentGroupPackage, final int numberOfElementsInTheCurrentGroup, final StackTraceElement firstStackTraceElementInTheGroup) {
if (numberOfElementsInTheCurrentGroup > 0) {
if (stackTraceElementSerializer == null) {
throw new IllegalArgumentException("Stack trace element serializer not initialized.");
} else {
stringBuilder.append((numberOfElementsInTheCurrentGroup == 1) ? stackTraceElementSerializer.toString(firstStackTraceElementInTheGroup) : String.format("%s%s ... %d more", stackTraceElementSerializer.getModuleName(firstStackTraceElementInTheGroup), currentGroupPackage, (numberOfElementsInTheCurrentGroup - 1)));
}
}
return 0;
}
/**
* <p>Returns true if package of the given class name matches one of package names provided in
* <code>packageSet</code>.
*
* @param fullClassName fully qualified class name
* @param packageSet set containing package names
* @return true if package of the given class name matches one of package names provided in <code>packageSet</code>,
* false otherwise
*/
public static boolean containsPackage(final String fullClassName, final Set<String> packageSet) {
return getContainingPackage(fullClassName, packageSet) != null;
}
/**
* <p>Checks if one of the package names in the <code>packageSet</code> matches the package of the given class name
* and returns the matching package name.
*
* @param fullClassName fully qualified class name
* @param packageSet set containing package names
* @return one of the package names in the <code>packageSet</code> that matches the package of the given class name
* or null if no matching package name is found in the <code>packageSet</code>
*/
public static String getContainingPackage(final String fullClassName, final Set<String> packageSet) {
for (final String parentExceptionPackage : packageSet) {
if (fullClassName.startsWith(parentExceptionPackage)) {
return parentExceptionPackage;
}
}
return null;
}
/**
* <p>Returns all messages found in the exception chain of the <code>throwable</code> as a single string.
*
* @param throwable parent throwable
* @return a string containing all messages found in the exception chain
*/
public static String getAllMessages(final Throwable throwable) {
final StringBuilder messageBuilder = new StringBuilder();
getAllMessages(throwable, messageBuilder);
return messageBuilder.toString();
}
/**
* <p>Adds all messages found in the exception chain of the <code>throwable</code> into the given message builder.
*
* @param throwable parent throwable
* @param messageBuilder message builder
*/
public static void getAllMessages(final Throwable throwable, final StringBuilder messageBuilder) {
if (throwable != null) {
final String message = throwable.getMessage();
if (!isEmpty(message)) {
if (messageBuilder.length() != 0) {
messageBuilder.append(System.lineSeparator());
messageBuilder.append(" - Caused by: ");
}
messageBuilder.append(message);
}
getAllMessages(throwable.getCause(), messageBuilder);
}
}
/**
* <p>Builds a smart stack trace for the given <code>throwable</code> using elements found until the maxDepth and
* elements of it.
*
* @param throwable parent throwable
* @param maxDepth max depth in exception chain that will be returned
* @return an array containing stack trace elements
*/
public static StackTraceElement[] getStackTrace(final Throwable throwable, final int maxDepth) {
final ArrayList<StackTraceElement> list = new ArrayList<StackTraceElement>();
if (throwable != null) {
StackTraceElement[] stackTrace = throwable.getStackTrace();
for (int i = 0; (i < stackTrace.length) && (i < maxDepth); i++) {
list.add(stackTrace[i]);
}
}
return list.toArray(new StackTraceElement[0]);
}
/**
* <p>Builds a smart stack trace for the given <code>throwable</code> using packages provided and returns elements
* of it.
*
* @param throwable parent throwable
* @param rootPackageSet root packages to use for building the stack trace
* @param ignorePackageSet ignore packages to use for building the stack trace
* @return an array containing stack trace elements
*/
public static StackTraceElement[] getStackTrace(final Throwable throwable, final Set<String> rootPackageSet, final Set<String> ignorePackageSet) {
final ArrayList<StackTraceElement> list = new ArrayList<StackTraceElement>();
final ArrayList<StackTraceElement> partialList = new ArrayList<StackTraceElement>();
if (throwable != null) {
for (StackTraceElement stackTraceElement : throwable.getStackTrace()) {
final String className = stackTraceElement.getClassName();
if (!isEmpty(className)) {
if (containsPackage(className, rootPackageSet)) {
list.addAll(partialList);
list.add(stackTraceElement);
} else if (!containsPackage(className, ignorePackageSet)) {
partialList.add(stackTraceElement);
}
}
}
}
if (list.isEmpty()) {
list.addAll(partialList);
}
return list.toArray(new StackTraceElement[0]);
}
/**
* <p>Returns true if the given cause class is found in the exception chain of the <code>throwable</code>.
* <br>
* <br>
* <p>Search starts from the <code>throwable</code> itself and goes through the exception chain up until
* {@link #DEFAULT_MAX_DEPTH}.
*
* @param throwable parent throwable
* @param causeClass class to search for
* @return true if the given cause class is found in the exception chain of the <code>throwable</code>, false
* otherwise
*/
public static boolean containsCause(final Throwable throwable, final Class<?> causeClass) {
return containsCause(throwable, causeClass, null);
}
/**
* <p>Returns true if the given cause class and cause message is found in the exception chain of the
* <code>throwable</code>.
* <br>
* <br>
* <p>Search starts from the <code>throwable</code> itself and goes through the exception chain up until
* {@link #DEFAULT_MAX_DEPTH}.
*
* @param throwable parent throwable
* @param causeClass class to search for
* @param causeMessage message to search for
* @return true if the given cause class and cause message is found in the exception chain of the
* <code>throwable</code>, false otherwise
*/
public static boolean containsCause(final Throwable throwable, final Class<?> causeClass, final String causeMessage) {
return (searchCause(throwable, causeClass, causeMessage, DEFAULT_MAX_DEPTH) != null);
}
/**
* <p>Returns the cause of the <code>throwable</code> by walking through the exception chain.
*
* @param throwable parent throwable
* @return the cause of the <code>throwable</code> found or null if <code>throwable</code> does not have a cause
*/
public static Throwable getCause(final Throwable throwable) {
return getCause(throwable, DEFAULT_MAX_DEPTH);
}
/**
* <p>Returns the cause of the <code>throwable</code> by walking through the exception chain.
* <br>
* <br>
* <p>Note that this method walks through the exception chain up to given <code>maxDepth</code>. If exception chain
* includes more items than <code>maxDepth</code>, cause found at <code>maxDepth</code> level is returned.
*
* @param throwable parent throwable
* @param maxDepth max depth in exception chain that will be searched
* @return the cause of the <code>throwable</code> found until <code>maxDepth</code> is reached in the exception
* chain or null if <code>throwable</code> does not have a cause
*/
public static Throwable getCause(final Throwable throwable, final int maxDepth) {
if (throwable == null) {
return null;
}
if (maxDepth <= 0) {
return throwable;
}
final Throwable cause = throwable.getCause();
if (cause == null) {
return throwable;
} else {
return getCause(cause, maxDepth - 1);
}
}
/**
* <p>Searches for the given cause class in the exception chain of the <code>throwable</code>.
* <br>
* <br>
* <p>Search starts from the <code>throwable</code> itself and goes through the exception chain up until
* {@link #DEFAULT_MAX_DEPTH}.
*
* @param throwable parent throwable
* @param causeClass class to search for
* @return the <code>throwable</code> found or null if no class in exception chain matches the given cause class
*/
public static Throwable searchCause(final Throwable throwable, final Class<?> causeClass) {
return searchCause(throwable, causeClass, null, DEFAULT_MAX_DEPTH);
}
/**
* <p>Searches for the given cause class and cause message in the exception chain of the <code>throwable</code>.
* <br>
* <br>
* <p>Search starts from the <code>throwable</code> itself and goes through the exception chain up until
* {@link #DEFAULT_MAX_DEPTH}.
*
* @param throwable parent throwable
* @param causeClass class to search for
* @param causeMessage message to search for
* @return the <code>throwable</code> found or null if no class in exception chain matches the given cause class
* and cause message
*/
public static Throwable searchCause(final Throwable throwable, final Class<?> causeClass, final String causeMessage) {
return searchCause(throwable, causeClass, causeMessage, DEFAULT_MAX_DEPTH);
}
/**
* <p>Searches for the given cause class and cause message in the exception chain of the <code>throwable</code>.
* <br>
* <br>
* <p>Search starts from the <code>throwable</code> itself and goes through the exception chain up until the given
* <code>maxDepth</code>.
*
* @param throwable parent throwable
* @param causeClass class to search for
* @param causeMessage message to search for
* @param maxDepth max depth in exception chain that will be searched
* @return the <code>throwable</code> found or null if no class in exception chain matches the given cause class
* and cause message
*/
public static Throwable searchCause(final Throwable throwable, final Class<?> causeClass, final String causeMessage, final int maxDepth) {
if (throwable == null) {
return null;
}
if (isEmpty(causeMessage)) {
if (throwable.getClass().equals(causeClass)) {
return throwable;
}
} else {
if (throwable.getClass().equals(causeClass) && getAllMessages(throwable).toLowerCase().contains(causeMessage.toLowerCase())) {
return throwable;
}
}
if (maxDepth <= 0) {
return null;
}
final Throwable cause = throwable.getCause();
if (cause == null) {
return null;
} else {
return searchCause(cause, causeClass, causeMessage, maxDepth - 1);
}
}
/**
* <p>Searches for the given cause class in the exception chain of the <code>throwable</code>.
* <br>
* <br>
* <p>Search starts from the <code>throwable</code> itself and goes through the exception chain up until the given
* <code>maxDepth</code>.
*
* @param throwable parent throwable
* @param causeClass class to search for
* @param maxDepth max depth in exception chain that will be searched
* @return the <code>throwable</code> found or null if no class in exception chain matches the given cause class
*/
public static Throwable searchCause(final Throwable throwable, final Class<?> causeClass, final int maxDepth) {
if (throwable == null) {
return null;
}
if (throwable.getClass().equals(causeClass)) {
return throwable;
}
if (maxDepth <= 0) {
return null;
}
final Throwable cause = throwable.getCause();
if (cause == null) {
return null;
} else {
return searchCause(cause, causeClass, maxDepth - 1);
}
}
/**
* <p>Checks if given string is empty or not.
*
* @param value string to check
* @return true if given string is null or has zero length after trim(), false otherwise
*/
public static boolean isEmpty(final String value) {
if (value == null) {
return true;
}
return value.trim().length() == 0;
}
/**
* <p>Returns the package name of this class.
*
* @param className fully qualified class name
* @return name of the package
*/
public static String packageName(final String className) {
if (className == null) {
return "";
}
int index = className.lastIndexOf(".");
if (index >= 0) {
return className.substring(0, index);
} else {
return "";
}
}
}
@@ -0,0 +1,74 @@
/*
* BSD 3-Clause License
*
* Copyright (c) 2020, Taner Sener
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.arthenica.smartexception;
/**
* <p>Base interface for classes which can serialize {@link StackTraceElement} objects.
*
* @author Taner Sener
* @since 0.1.0
*/
public interface StackTraceElementSerializer {
/**
* <p>Converts the given <code>stackTraceElement</code> into a string.
*
* @param stackTraceElement stack trace element to convert
* @return string representing the given <code>stackTraceElement</code>
*/
String toString(final StackTraceElement stackTraceElement);
/**
* <p>Returns module name for the given <code>stackTraceElement</code>.
*
* @param stackTraceElement stack trace element to use
* @return module name of the given <code>stackTraceElement</code> or an empty string if implementation does not
* support printing module names
*/
String getModuleName(final StackTraceElement stackTraceElement);
/**
* <p>Returns string definition used to print native methods.
*
* @return string definition used to print native methods
*/
String getNativeMethodDefinition();
/**
* <p>Returns string definition used to print methods with unknown source.
*
* @return string definition used to print methods with unknown source
*/
String getUnknownSourceDefinition();
}
@@ -0,0 +1,423 @@
/*
* BSD 3-Clause License
*
* Copyright (c) 2020, Taner Sener
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.arthenica.smartexception.java;
import com.arthenica.smartexception.AbstractExceptions;
import com.arthenica.smartexception.StackTraceElementSerializer;
import java.util.Set;
/**
* <p>Utility class to handle Throwable objects and stack traces. This implementation is compatible with all Java and
* Android versions.
*
* @author Taner Sener
* @since 0.1.0
*/
public class Exceptions {
static {
AbstractExceptions.setStackTraceElementSerializer(new StackTraceElementSerializer() {
@Override
public String toString(StackTraceElement stackTraceElement) {
final StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(stackTraceElement.getClassName());
stringBuilder.append(".");
stringBuilder.append(stackTraceElement.getMethodName());
if (stackTraceElement.isNativeMethod()) {
stringBuilder.append("(Native Method)");
} else if ((stackTraceElement.getFileName() != null) && (stackTraceElement.getFileName().length() > 0)) {
stringBuilder.append("(");
stringBuilder.append(stackTraceElement.getFileName());
if (stackTraceElement.getLineNumber() >= 0) {
stringBuilder.append(":");
stringBuilder.append(stackTraceElement.getLineNumber());
}
stringBuilder.append(")");
} else {
stringBuilder.append("(Unknown Source)");
}
return stringBuilder.toString();
}
@Override
public String getModuleName(StackTraceElement stackTraceElement) {
return "";
}
@Override
public String getNativeMethodDefinition() {
return "(Native Method)";
}
@Override
public String getUnknownSourceDefinition() {
return "(Unknown Source)";
}
});
}
/**
* <p>Registers a new root package.
*
* @param packageString root package name to register
*/
public static void registerRootPackage(final String packageString) {
AbstractExceptions.registerRootPackage(packageString);
}
/**
* <p>Clears previously registered root packages.
*/
public static void clearRootPackages() {
AbstractExceptions.clearRootPackages();
}
/**
* <p>Registers a new group package.
*
* @param packageString group package name to register
*/
public static void registerGroupPackage(final String packageString) {
AbstractExceptions.registerGroupPackage(packageString);
}
/**
* <p>Clears previously registered group packages.
*/
public static void clearGroupPackages() {
AbstractExceptions.clearGroupPackages();
}
/**
* <p>Returns the global stack trace serializer implementation which is used to serialize {@link StackTraceElement}
* objects in <code>getStackTraceString</code> methods.
*
* @return current stack trace serializer implementation
*/
public static StackTraceElementSerializer getStackTraceElementSerializer() {
return AbstractExceptions.getStackTraceElementSerializer();
}
/**
* <p>Sets the global stack trace serializer implementation which is used to serialize {@link StackTraceElement}
* objects in <code>getStackTraceString</code> methods.
*
* @param stackTraceElementSerializer new stack trace serializer implementation
*/
public static void setStackTraceElementSerializer(final StackTraceElementSerializer stackTraceElementSerializer) {
AbstractExceptions.setStackTraceElementSerializer(stackTraceElementSerializer);
}
/**
* <p>Registers a new ignore package.
*
* @param packageString ignore package name to register
* @param ignoreCauseClasses ignore cause classes from this package too
*/
public static void registerIgnorePackage(final String packageString, final boolean ignoreCauseClasses) {
AbstractExceptions.registerIgnorePackage(packageString, ignoreCauseClasses);
}
/**
* <p>Clears previously registered ignore packages.
*/
public static void clearIgnorePackages() {
AbstractExceptions.clearIgnorePackages();
}
/**
* <p>Returns the value of ignore all causes option.
*
* @return the value of global ignore all causes option. If value is true then stack trace elements printed or
* converted to string will not include causes. If value is false causes will be appended to the stack trace of
* the main throwable.
*/
public static boolean getIgnoreAllCauses() {
return AbstractExceptions.getIgnoreAllCauses();
}
/**
* <p>Sets the value of ignore all causes option.
*
* @param ignoreAllCauses new global ignore all causes option. If value is true then stack trace elements printed
* or converted to string will not include causes. If value is false causes will be appended to the stack trace of
* the main throwable.
*/
public static void setIgnoreAllCauses(final boolean ignoreAllCauses) {
AbstractExceptions.setIgnoreAllCauses(ignoreAllCauses);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code>.
*
* <p>This method uses root packages registered by {@link #registerRootPackage(String)}, group packages registered
* by {@link #registerGroupPackage(String)} and ignore packages registered by
* {@link #registerIgnorePackage(String, boolean)} to build the smart stack trace.
*
* @param throwable parent throwable
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable) {
return AbstractExceptions.getStackTraceString(throwable);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code>.
*
* <p>This method uses root packages registered by {@link #registerRootPackage(String)}, group packages registered
* by {@link #registerGroupPackage(String)} and ignore packages registered by
* {@link #registerIgnorePackage(String, boolean)} to build the smart stack trace.
*
* @param throwable parent throwable
* @param ignoreAllCauses ignore all causes in the exception chain
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable, final boolean ignoreAllCauses) {
return AbstractExceptions.getStackTraceString(throwable, ignoreAllCauses);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code> using packages provided.
*
* @param throwable parent throwable
* @param rootPackageSet root packages to use for building the stack trace
* @param groupPackageSet group packages to use for building the stack trace
* @param ignorePackageSet ignore packages to use for building the stack trace
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable, final Set<String> rootPackageSet, final Set<String> groupPackageSet, final Set<String> ignorePackageSet) {
return AbstractExceptions.getStackTraceString(throwable, rootPackageSet, groupPackageSet, ignorePackageSet);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code> using packages provided.
*
* @param throwable parent throwable
* @param rootPackageSet root packages to use for building the stack trace
* @param groupPackageSet group packages to use for building the stack trace
* @param ignorePackageSet ignore packages to use for building the stack trace
* @param ignoreAllCauses ignore all causes in the exception chain
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable, final Set<String> rootPackageSet, final Set<String> groupPackageSet, final Set<String> ignorePackageSet, final boolean ignoreAllCauses) {
return AbstractExceptions.getStackTraceString(throwable, rootPackageSet, groupPackageSet, ignorePackageSet, ignoreAllCauses);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code> using root package provided.
*
* @param throwable parent throwable
* @param rootPackage root package to use for building the stack trace
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable, final String rootPackage) {
return AbstractExceptions.getStackTraceString(throwable, rootPackage);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code> using root package provided.
*
* @param throwable parent throwable
* @param rootPackage root package to use for building the stack trace
* @param groupPackage group package to use for building the stack trace
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable, final String rootPackage, final String groupPackage) {
return AbstractExceptions.getStackTraceString(throwable, rootPackage, groupPackage);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code> using elements found until the maxDepth.
*
* @param throwable parent throwable
* @param maxDepth max depth in exception chain that will be used
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable, final int maxDepth) {
return AbstractExceptions.getStackTraceString(throwable, maxDepth);
}
/**
* <p>Returns the smart stack trace for the given <code>throwable</code> using elements found until the maxDepth.
*
* @param throwable parent throwable
* @param maxDepth max depth in exception chain that will be used
* @param ignoreAllCauses ignore all causes in the exception chain
* @return a string containing the smart stack trace for the given <code>throwable</code>
*/
public static String getStackTraceString(final Throwable throwable, final int maxDepth, final boolean ignoreAllCauses) {
return AbstractExceptions.getStackTraceString(throwable, maxDepth, ignoreAllCauses);
}
/**
* <p>Returns all messages found in the exception chain of the <code>throwable</code> as a single string.
*
* @param throwable parent throwable
* @return a string containing all messages found in the exception chain
*/
public static String getAllMessages(final Throwable throwable) {
return AbstractExceptions.getAllMessages(throwable);
}
/**
* <p>Returns true if the given cause class is found in the exception chain of the <code>throwable</code>.
* <br>
* <br>
* <p>Search starts from the <code>throwable</code> itself and goes through the exception chain up until
* {@link AbstractExceptions#DEFAULT_MAX_DEPTH}.
*
* @param throwable parent throwable
* @param causeClass class to search for
* @return true if the given cause class is found in the exception chain of the <code>throwable</code>, false
* otherwise
*/
public static boolean containsCause(final Throwable throwable, final Class<?> causeClass) {
return AbstractExceptions.containsCause(throwable, causeClass);
}
/**
* <p>Returns true if the given cause class and cause message is found in the exception chain of the
* <code>throwable</code>.
* <br>
* <br>
* <p>Search starts from the <code>throwable</code> itself and goes through the exception chain up until
* {@link AbstractExceptions#DEFAULT_MAX_DEPTH}.
*
* @param throwable parent throwable
* @param causeClass class to search for
* @param causeMessage message to search for
* @return true if the given cause class and cause message is found in the exception chain of the
* <code>throwable</code>, false otherwise
*/
public static boolean containsCause(final Throwable throwable, final Class<?> causeClass, final String causeMessage) {
return AbstractExceptions.containsCause(throwable, causeClass, causeMessage);
}
/**
* <p>Returns the cause of the <code>throwable</code> by walking through the exception chain.
*
* @param throwable parent throwable
* @return the cause of the <code>throwable</code> found or null if <code>throwable</code> does not have a cause
*/
public static Throwable getCause(final Throwable throwable) {
return AbstractExceptions.getCause(throwable);
}
/**
* <p>Returns the cause of the <code>throwable</code> by walking through the exception chain.
* <br>
* <br>
* <p>Note that this method walks through the exception chain up to given <code>maxDepth</code>. If exception chain
* includes more items than <code>maxDepth</code>, cause found at <code>maxDepth</code> level is returned.
*
* @param throwable parent throwable
* @param maxDepth max depth in exception chain that will be searched
* @return the cause of the <code>throwable</code> found until <code>maxDepth</code> is reached in the exception
* chain or null if <code>throwable</code> does not have a cause
*/
public static Throwable getCause(final Throwable throwable, final int maxDepth) {
return AbstractExceptions.getCause(throwable, maxDepth);
}
/**
* <p>Searches for the given cause class in the exception chain of the <code>throwable</code>.
* <br>
* <br>
* <p>Search starts from the <code>throwable</code> itself and goes through the exception chain up until
* {@link AbstractExceptions#DEFAULT_MAX_DEPTH}.
*
* @param throwable parent throwable
* @param causeClass class to search for
* @return the <code>throwable</code> found or null if no class in exception chain matches the given cause class
*/
public static Throwable searchCause(final Throwable throwable, final Class<?> causeClass) {
return AbstractExceptions.searchCause(throwable, causeClass);
}
/**
* <p>Searches for the given cause class and cause message in the exception chain of the <code>throwable</code>.
* <br>
* <br>
* <p>Search starts from the <code>throwable</code> itself and goes through the exception chain up until
* {@link AbstractExceptions#DEFAULT_MAX_DEPTH}.
*
* @param throwable parent throwable
* @param causeClass class to search for
* @param causeMessage message to search for
* @return the <code>throwable</code> found or null if no class in exception chain matches the given cause class
* and cause message
*/
public static Throwable searchCause(final Throwable throwable, final Class<?> causeClass, final String causeMessage) {
return AbstractExceptions.searchCause(throwable, causeClass, causeMessage);
}
/**
* <p>Searches for the given cause class and cause message in the exception chain of the <code>throwable</code>.
* <br>
* <br>
* <p>Search starts from the <code>throwable</code> itself and goes through the exception chain up until the given
* <code>maxDepth</code>.
*
* @param throwable parent throwable
* @param causeClass class to search for
* @param causeMessage message to search for
* @param maxDepth max depth in exception chain that will be searched
* @return the <code>throwable</code> found or null if no class in exception chain matches the given cause class
* and cause message
*/
public static Throwable searchCause(final Throwable throwable, final Class<?> causeClass, final String causeMessage, final int maxDepth) {
return AbstractExceptions.searchCause(throwable, causeClass, causeMessage, maxDepth);
}
/**
* <p>Searches for the given cause class in the exception chain of the <code>throwable</code>.
* <br>
* <br>
* <p>Search starts from the <code>throwable</code> itself and goes through the exception chain up until the given
* <code>maxDepth</code>.
*
* @param throwable parent throwable
* @param causeClass class to search for
* @param maxDepth max depth in exception chain that will be searched
* @return the <code>throwable</code> found or null if no class in exception chain matches the given cause class
*/
public static Throwable searchCause(final Throwable throwable, final Class<?> causeClass, final int maxDepth) {
return AbstractExceptions.searchCause(throwable, causeClass, maxDepth);
}
}
@@ -35,47 +35,33 @@ import java.util.Map.Entry;
*/ */
public class ArscBlamer { public class ArscBlamer {
/** /** Maps package key pool indices to blamed resources. */
* Maps package key pool indices to blamed resources.
*/
private final Map<PackageChunk, List<ResourceEntry>[]> keyToBlame = new HashMap<>(); private final Map<PackageChunk, List<ResourceEntry>[]> keyToBlame = new HashMap<>();
/** /** Maps types to blamed resources. */
* Maps types to blamed resources.
*/
private final Map<PackageChunk, List<ResourceEntry>[]> typeToBlame = new HashMap<>(); private final Map<PackageChunk, List<ResourceEntry>[]> typeToBlame = new HashMap<>();
/** /** Maps package to blamed resources. */
* Maps package to blamed resources.
*/
private final Multimap<PackageChunk, ResourceEntry> packageToBlame = HashMultimap.create(); private final Multimap<PackageChunk, ResourceEntry> packageToBlame = HashMultimap.create();
/** /** Maps string indices to blamed resources. */
* Maps string indices to blamed resources.
*/
private final List<ResourceEntry>[] stringToBlame; private final List<ResourceEntry>[] stringToBlame;
/** /** Maps type chunk entries to blamed resources. */
* Maps type chunk entries to blamed resources.
*/
private final Multimap<TypeChunk.Entry, ResourceEntry> typeEntryToBlame = HashMultimap.create(); private final Multimap<TypeChunk.Entry, ResourceEntry> typeEntryToBlame = HashMultimap.create();
/**
* This is the {@link ResourceTableChunk} inside of the resources.arsc file in the APK. /** Maps resources to the type chunk entries they reference. */
*/
private final ResourceTableChunk resourceTable;
/**
* Maps resources to the type chunk entries they reference.
*/
private Multimap<ResourceEntry, TypeChunk.Entry> resourceEntries; private Multimap<ResourceEntry, TypeChunk.Entry> resourceEntries;
/**
* Maps resources which have no base config to the type chunk entries they reference. /** Maps resources which have no base config to the type chunk entries they reference. */
*/
private Multimap<ResourceEntry, TypeChunk.Entry> baselessKeys; private Multimap<ResourceEntry, TypeChunk.Entry> baselessKeys;
/**
* Contains all of the type chunks in {@link #resourceTable}. /** Contains all of the type chunks in {@link #resourceTable}. */
*/
private List<TypeChunk> typeChunks; private List<TypeChunk> typeChunks;
/** This is the {@link ResourceTableChunk} inside of the resources.arsc file in the APK. */
private final ResourceTableChunk resourceTable;
/** /**
* Creates a new {@link ArscBlamer}. * Creates a new {@link ArscBlamer}.
* *
@@ -86,17 +72,7 @@ public class ArscBlamer {
this.stringToBlame = createEntryListArray(resourceTable.getStringPool().getStringCount()); this.stringToBlame = createEntryListArray(resourceTable.getStringPool().getStringCount());
} }
private static List<ResourceEntry>[] createEntryListArray(int size) { /** Generates blame mappings. */
ArrayListResourceEntry[] result = new ArrayListResourceEntry[size];
for (int i = 0; i < size; ++i) {
result[i] = new ArrayListResourceEntry();
}
return result;
}
/**
* Generates blame mappings.
*/
public void blame() { public void blame() {
Multimap<ResourceEntry, TypeChunk.Entry> entries = getResourceEntries(); Multimap<ResourceEntry, TypeChunk.Entry> entries = getResourceEntries();
for (Entry<ResourceEntry, Collection<TypeChunk.Entry>> entry : entries.asMap().entrySet()) { for (Entry<ResourceEntry, Collection<TypeChunk.Entry>> entry : entries.asMap().entrySet()) {
@@ -145,9 +121,7 @@ public class ArscBlamer {
} }
} }
/** /** Returns all {@link BinaryResourceValue} for a single {@code entry}. */
* Returns all {@link BinaryResourceValue} for a single {@code entry}.
*/
private Collection<BinaryResourceValue> getAllResourceValues(TypeChunk.Entry entry) { private Collection<BinaryResourceValue> getAllResourceValues(TypeChunk.Entry entry) {
Set<BinaryResourceValue> values = new HashSet<BinaryResourceValue>(); Set<BinaryResourceValue> values = new HashSet<BinaryResourceValue>();
BinaryResourceValue binaryResourceValue = entry.value(); BinaryResourceValue binaryResourceValue = entry.value();
@@ -164,44 +138,32 @@ public class ArscBlamer {
stringToBlame[stringIndex].add(entry); stringToBlame[stringIndex].add(entry);
} }
/** /** Must first call {@link #blame}. */
* Must first call {@link #blame}.
*/
public Map<PackageChunk, List<ResourceEntry>[]> getKeyToBlamedResources() { public Map<PackageChunk, List<ResourceEntry>[]> getKeyToBlamedResources() {
return Collections.unmodifiableMap(keyToBlame); return Collections.unmodifiableMap(keyToBlame);
} }
/** /** Must first call {@link #blame}. */
* Must first call {@link #blame}.
*/
public Map<PackageChunk, List<ResourceEntry>[]> getTypeToBlamedResources() { public Map<PackageChunk, List<ResourceEntry>[]> getTypeToBlamedResources() {
return Collections.unmodifiableMap(typeToBlame); return Collections.unmodifiableMap(typeToBlame);
} }
/** /** Must first call {@link #blame}. */
* Must first call {@link #blame}.
*/
public Multimap<PackageChunk, ResourceEntry> getPackageToBlamedResources() { public Multimap<PackageChunk, ResourceEntry> getPackageToBlamedResources() {
return Multimaps.unmodifiableMultimap(packageToBlame); return Multimaps.unmodifiableMultimap(packageToBlame);
} }
/** /** Must first call {@link #blame}. */
* Must first call {@link #blame}.
*/
public List<ResourceEntry>[] getStringToBlamedResources() { public List<ResourceEntry>[] getStringToBlamedResources() {
return stringToBlame; return stringToBlame;
} }
/** /** Must first call {@link #blame}. */
* Must first call {@link #blame}.
*/
public Multimap<TypeChunk.Entry, ResourceEntry> getTypeEntryToBlamedResources() { public Multimap<TypeChunk.Entry, ResourceEntry> getTypeEntryToBlamedResources() {
return Multimaps.unmodifiableMultimap(typeEntryToBlame); return Multimaps.unmodifiableMultimap(typeEntryToBlame);
} }
/** /** Returns a multimap of keys for which there is no default resource. */
* Returns a multimap of keys for which there is no default resource.
*/
public Multimap<ResourceEntry, TypeChunk.Entry> getBaselessKeys() { public Multimap<ResourceEntry, TypeChunk.Entry> getBaselessKeys() {
if (baselessKeys != null) { if (baselessKeys != null) {
return baselessKeys; return baselessKeys;
@@ -218,9 +180,7 @@ public class ArscBlamer {
return result; return result;
} }
/** /** Returns a multimap of resource entries to the chunk entries they reference in this APK. */
* Returns a multimap of resource entries to the chunk entries they reference in this APK.
*/
public Multimap<ResourceEntry, TypeChunk.Entry> getResourceEntries() { public Multimap<ResourceEntry, TypeChunk.Entry> getResourceEntries() {
if (resourceEntries != null) { if (resourceEntries != null) {
return resourceEntries; return resourceEntries;
@@ -235,9 +195,7 @@ public class ArscBlamer {
return result; return result;
} }
/** /** Returns all {@link TypeChunk} in resources.arsc. */
* Returns all {@link TypeChunk} in resources.arsc.
*/
public List<TypeChunk> getTypeChunks() { public List<TypeChunk> getTypeChunks() {
if (typeChunks != null) { if (typeChunks != null) {
return typeChunks; return typeChunks;
@@ -261,9 +219,15 @@ public class ArscBlamer {
return false; return false;
} }
/** private static List<ResourceEntry>[] createEntryListArray(int size) {
* Allows creation of concrete parameterized type arr {@link ArscBlamer#createEntryListArray}. ArrayListResourceEntry[] result = new ArrayListResourceEntry[size];
*/ for (int i = 0; i < size; ++i) {
result[i] = new ArrayListResourceEntry();
}
return result;
}
/** Allows creation of concrete parameterized type arr {@link ArscBlamer#createEntryListArray}. */
private static class ArrayListResourceEntry extends ArrayList<ResourceEntry> { private static class ArrayListResourceEntry extends ArrayList<ResourceEntry> {
private ArrayListResourceEntry() { private ArrayListResourceEntry() {
@@ -271,20 +235,12 @@ public class ArscBlamer {
} }
} }
/** /** Describes a single resource entry. */
* Describes a single resource entry.
*/
public static class ResourceEntry { public static class ResourceEntry {
private final String packageName; private final String packageName;
private final String typeName; private final String typeName;
private final String entryName; private final String entryName;
private ResourceEntry(String packageName, String typeName, String entryName) {
this.packageName = packageName;
this.typeName = typeName;
this.entryName = entryName;
}
static ResourceEntry create(TypeChunk.Entry entry) { static ResourceEntry create(TypeChunk.Entry entry) {
PackageChunk packageChunk = Preconditions.checkNotNull(entry.parent().getPackageChunk()); PackageChunk packageChunk = Preconditions.checkNotNull(entry.parent().getPackageChunk());
String packageName = packageChunk.getPackageName(); String packageName = packageChunk.getPackageName();
@@ -293,23 +249,21 @@ public class ArscBlamer {
return new ResourceEntry(packageName, typeName, entryName); return new ResourceEntry(packageName, typeName, entryName);
} }
public String packageName() { private ResourceEntry(String packageName, String typeName, String entryName) {
return packageName; this.packageName = packageName;
this.typeName = typeName;
this.entryName = entryName;
} }
public String typeName() { public String packageName() { return packageName; }
return typeName; public String typeName() { return typeName; }
} public String entryName() { return entryName; }
public String entryName() {
return entryName;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
ResourceEntry that = (ResourceEntry) o; ResourceEntry that = (ResourceEntry)o;
return Objects.equals(packageName, that.packageName) && return Objects.equals(packageName, that.packageName) &&
Objects.equals(typeName, that.typeName) && Objects.equals(typeName, that.typeName) &&
Objects.equals(entryName, that.entryName); Objects.equals(entryName, that.entryName);
@@ -31,148 +31,6 @@ import static java.nio.charset.StandardCharsets.US_ASCII;
* Describes a particular resource configuration. * Describes a particular resource configuration.
*/ */
public class BinaryResourceConfiguration implements SerializableResource { public class BinaryResourceConfiguration implements SerializableResource {
/**
* The below constants are from android.content.res.Configuration.
*/
private static final int DENSITY_DPI_UNDEFINED = 0;
private static final int DENSITY_DPI_LDPI = 120;
private static final int DENSITY_DPI_MDPI = 160;
private static final int DENSITY_DPI_TVDPI = 213;
private static final int DENSITY_DPI_HDPI = 240;
private static final int DENSITY_DPI_XHDPI = 320;
private static final int DENSITY_DPI_XXHDPI = 480;
private static final int DENSITY_DPI_XXXHDPI = 640;
private static final int DENSITY_DPI_ANY = 0xFFFE;
private static final int DENSITY_DPI_NONE = 0xFFFF;
private static final Map<Integer, String> DENSITY_DPI_VALUES =
ImmutableMap.<Integer, String>builder()
.put(DENSITY_DPI_UNDEFINED, "")
.put(DENSITY_DPI_LDPI, "ldpi")
.put(DENSITY_DPI_MDPI, "mdpi")
.put(DENSITY_DPI_TVDPI, "tvdpi")
.put(DENSITY_DPI_HDPI, "hdpi")
.put(DENSITY_DPI_XHDPI, "xhdpi")
.put(DENSITY_DPI_XXHDPI, "xxhdpi")
.put(DENSITY_DPI_XXXHDPI, "xxxhdpi")
.put(DENSITY_DPI_ANY, "anydpi")
.put(DENSITY_DPI_NONE, "nodpi")
.build();
private static final int KEYBOARD_NOKEYS = 1;
private static final int KEYBOARD_QWERTY = 2;
private static final int KEYBOARD_12KEY = 3;
private static final Map<Integer, String> KEYBOARD_VALUES = ImmutableMap.of(
KEYBOARD_NOKEYS, "nokeys",
KEYBOARD_QWERTY, "qwerty",
KEYBOARD_12KEY, "12key");
private static final int KEYBOARDHIDDEN_MASK = 0x03;
private static final int KEYBOARDHIDDEN_NO = 1;
private static final int KEYBOARDHIDDEN_YES = 2;
private static final int KEYBOARDHIDDEN_SOFT = 3;
private static final Map<Integer, String> KEYBOARDHIDDEN_VALUES = ImmutableMap.of(
KEYBOARDHIDDEN_NO, "keysexposed",
KEYBOARDHIDDEN_YES, "keyshidden",
KEYBOARDHIDDEN_SOFT, "keyssoft");
private static final int NAVIGATION_NONAV = 1;
private static final int NAVIGATION_DPAD = 2;
private static final int NAVIGATION_TRACKBALL = 3;
private static final int NAVIGATION_WHEEL = 4;
private static final Map<Integer, String> NAVIGATION_VALUES = ImmutableMap.of(
NAVIGATION_NONAV, "nonav",
NAVIGATION_DPAD, "dpad",
NAVIGATION_TRACKBALL, "trackball",
NAVIGATION_WHEEL, "wheel");
private static final int NAVIGATIONHIDDEN_MASK = 0x0C;
private static final int NAVIGATIONHIDDEN_NO = 0x04;
private static final int NAVIGATIONHIDDEN_YES = 0x08;
private static final Map<Integer, String> NAVIGATIONHIDDEN_VALUES = ImmutableMap.of(
NAVIGATIONHIDDEN_NO, "navexposed",
NAVIGATIONHIDDEN_YES, "navhidden");
private static final int ORIENTATION_PORTRAIT = 0x01;
private static final int ORIENTATION_LANDSCAPE = 0x02;
private static final Map<Integer, String> ORIENTATION_VALUES = ImmutableMap.of(
ORIENTATION_PORTRAIT, "port",
ORIENTATION_LANDSCAPE, "land");
private static final int SCREENLAYOUT_LAYOUTDIR_MASK = 0xC0;
private static final int SCREENLAYOUT_LAYOUTDIR_LTR = 0x40;
private static final int SCREENLAYOUT_LAYOUTDIR_RTL = 0x80;
private static final Map<Integer, String> SCREENLAYOUT_LAYOUTDIR_VALUES = ImmutableMap.of(
SCREENLAYOUT_LAYOUTDIR_LTR, "ldltr",
SCREENLAYOUT_LAYOUTDIR_RTL, "ldrtl");
private static final int SCREENLAYOUT_LONG_MASK = 0x30;
private static final int SCREENLAYOUT_LONG_NO = 0x10;
private static final int SCREENLAYOUT_LONG_YES = 0x20;
private static final Map<Integer, String> SCREENLAYOUT_LONG_VALUES = ImmutableMap.of(
SCREENLAYOUT_LONG_NO, "notlong",
SCREENLAYOUT_LONG_YES, "long");
private static final int SCREENLAYOUT_ROUND_MASK = 0x03;
private static final int SCREENLAYOUT_ROUND_NO = 0x01;
private static final int SCREENLAYOUT_ROUND_YES = 0x02;
private static final Map<Integer, String> SCREENLAYOUT_ROUND_VALUES = ImmutableMap.of(
SCREENLAYOUT_ROUND_NO, "notround",
SCREENLAYOUT_ROUND_YES, "round");
private static final int SCREENLAYOUT_SIZE_MASK = 0x0F;
private static final int SCREENLAYOUT_SIZE_SMALL = 0x01;
private static final int SCREENLAYOUT_SIZE_NORMAL = 0x02;
private static final int SCREENLAYOUT_SIZE_LARGE = 0x03;
private static final int SCREENLAYOUT_SIZE_XLARGE = 0x04;
private static final Map<Integer, String> SCREENLAYOUT_SIZE_VALUES = ImmutableMap.of(
SCREENLAYOUT_SIZE_SMALL, "small",
SCREENLAYOUT_SIZE_NORMAL, "normal",
SCREENLAYOUT_SIZE_LARGE, "large",
SCREENLAYOUT_SIZE_XLARGE, "xlarge");
private static final int TOUCHSCREEN_NOTOUCH = 1;
private static final int TOUCHSCREEN_FINGER = 3;
private static final Map<Integer, String> TOUCHSCREEN_VALUES = ImmutableMap.of(
TOUCHSCREEN_NOTOUCH, "notouch",
TOUCHSCREEN_FINGER, "finger");
private static final int UI_MODE_NIGHT_MASK = 0x30;
private static final int UI_MODE_NIGHT_NO = 0x10;
private static final int UI_MODE_NIGHT_YES = 0x20;
private static final Map<Integer, String> UI_MODE_NIGHT_VALUES = ImmutableMap.of(
UI_MODE_NIGHT_NO, "notnight",
UI_MODE_NIGHT_YES, "night");
private static final int UI_MODE_TYPE_MASK = 0x0F;
private static final int UI_MODE_TYPE_DESK = 0x02;
private static final int UI_MODE_TYPE_CAR = 0x03;
private static final int UI_MODE_TYPE_TELEVISION = 0x04;
private static final int UI_MODE_TYPE_APPLIANCE = 0x05;
private static final int UI_MODE_TYPE_WATCH = 0x06;
private static final int UI_MODE_TYPE_VR_HEADSET = 0x07;
// start - miui
private static final int UI_MODE_TYPE_GODZILLAUI = 0x0b;
private static final int UI_MODE_TYPE_SMALLUI = 0x0c;
private static final int UI_MODE_TYPE_MEDIUMUI = 0x0d;
private static final int UI_MODE_TYPE_LARGEUI = 0x0e;
private static final int UI_MODE_TYPE_HUGEUI = 0x0f;
private static final Map<Integer, String> UI_MODE_TYPE_VALUES =
ImmutableMap.<Integer, String>builder()
.put(UI_MODE_TYPE_DESK, "desk")
.put(UI_MODE_TYPE_CAR, "car")
.put(UI_MODE_TYPE_TELEVISION, "television")
.put(UI_MODE_TYPE_APPLIANCE, "appliance")
.put(UI_MODE_TYPE_WATCH, "watch")
.put(UI_MODE_TYPE_VR_HEADSET, "vrheadset")
.put(UI_MODE_TYPE_GODZILLAUI, "godzillaui")
.put(UI_MODE_TYPE_SMALLUI, "smallui")
.put(UI_MODE_TYPE_MEDIUMUI, "mediumui")
.put(UI_MODE_TYPE_LARGEUI, "largeui")
.put(UI_MODE_TYPE_HUGEUI, "hugeui").build();
/**
* The minimum size in bytes that this configuration must be to contain screen config info.
*/
private static final int SCREEN_CONFIG_MIN_SIZE = 32;
/**
* The minimum size in bytes that this configuration must be to contain screen dp info.
*/
private static final int SCREEN_DP_MIN_SIZE = 36;
/**
* The minimum size in bytes that this configuration must be to contain locale info.
*/
private static final int LOCALE_MIN_SIZE = 48;
/**
* The minimum size in bytes that this config must be to contain the screenConfig extension.
*/
private static final int SCREEN_CONFIG_EXTENSION_MIN_SIZE = 52;
private final int size; private final int size;
private final int mcc; private final int mcc;
private final int mnc; private final int mnc;
@@ -195,60 +53,9 @@ public class BinaryResourceConfiguration implements SerializableResource {
private final int screenHeightDp; private final int screenHeightDp;
private final byte[] localeScript; private final byte[] localeScript;
private final byte[] localeVariant; private final byte[] localeVariant;
// end - miui
private final int screenLayout2; private final int screenLayout2;
private final byte[] unknown; private final byte[] unknown;
private BinaryResourceConfiguration(int size,
int mcc,
int mnc,
byte[] language,
byte[] region,
int orientation,
int touchscreen,
int density,
int keyboard,
int navigation,
int inputFlags,
int screenWidth,
int screenHeight,
int sdkVersion,
int minorVersion,
int screenLayout,
int uiMode,
int smallestScreenWidthDp,
int screenWidthDp,
int screenHeightDp,
byte[] localeScript,
byte[] localeVariant,
int screenLayout2,
byte[] unknown) {
this.size = size;
this.mcc = mcc;
this.mnc = mnc;
this.language = language;
this.region = region;
this.orientation = orientation;
this.touchscreen = touchscreen;
this.density = density;
this.keyboard = keyboard;
this.navigation = navigation;
this.inputFlags = inputFlags;
this.screenWidth = screenWidth;
this.screenHeight = screenHeight;
this.sdkVersion = sdkVersion;
this.minorVersion = minorVersion;
this.screenLayout = screenLayout;
this.uiMode = uiMode;
this.smallestScreenWidthDp = smallestScreenWidthDp;
this.screenWidthDp = screenWidthDp;
this.screenHeightDp = screenHeightDp;
this.localeScript = localeScript;
this.localeVariant = localeVariant;
this.screenLayout2 = screenLayout2;
this.unknown = unknown;
}
static BinaryResourceConfiguration create(ByteBuffer buffer) { static BinaryResourceConfiguration create(ByteBuffer buffer) {
int startPosition = buffer.position(); // The starting buffer position to calculate bytes read. int startPosition = buffer.position(); // The starting buffer position to calculate bytes read.
int size = buffer.getInt(); int size = buffer.getInt();
@@ -314,6 +121,245 @@ public class BinaryResourceConfiguration implements SerializableResource {
screenHeightDp, localeScript, localeVariant, screenLayout2, unknown); screenHeightDp, localeScript, localeVariant, screenLayout2, unknown);
} }
private BinaryResourceConfiguration(int size,
int mcc,
int mnc,
byte[] language,
byte[] region,
int orientation,
int touchscreen,
int density,
int keyboard,
int navigation,
int inputFlags,
int screenWidth,
int screenHeight,
int sdkVersion,
int minorVersion,
int screenLayout,
int uiMode,
int smallestScreenWidthDp,
int screenWidthDp,
int screenHeightDp,
byte[] localeScript,
byte[] localeVariant,
int screenLayout2,
byte[] unknown) {
this.size = size;
this.mcc = mcc;
this.mnc = mnc;
this.language = language;
this.region = region;
this.orientation = orientation;
this.touchscreen = touchscreen;
this.density = density;
this.keyboard = keyboard;
this.navigation = navigation;
this.inputFlags = inputFlags;
this.screenWidth = screenWidth;
this.screenHeight = screenHeight;
this.sdkVersion = sdkVersion;
this.minorVersion = minorVersion;
this.screenLayout = screenLayout;
this.uiMode = uiMode;
this.smallestScreenWidthDp = smallestScreenWidthDp;
this.screenWidthDp = screenWidthDp;
this.screenHeightDp = screenHeightDp;
this.localeScript = localeScript;
this.localeVariant = localeVariant;
this.screenLayout2 = screenLayout2;
this.unknown = unknown;
}
/**
* The different types of configs that can be present in a {@link BinaryResourceConfiguration}.
*/
public enum Type {
MCC,
MNC,
LANGUAGE_STRING,
REGION_STRING,
SCREEN_LAYOUT_DIRECTION,
SMALLEST_SCREEN_WIDTH_DP,
SCREEN_WIDTH_DP,
SCREEN_HEIGHT_DP,
SCREEN_LAYOUT_SIZE,
SCREEN_LAYOUT_LONG,
SCREEN_LAYOUT_ROUND,
ORIENTATION,
UI_MODE_TYPE,
UI_MODE_NIGHT,
DENSITY_DPI,
TOUCHSCREEN,
KEYBOARD_HIDDEN,
KEYBOARD,
NAVIGATION_HIDDEN,
NAVIGATION,
SDK_VERSION
}
/**
* The below constants are from android.content.res.Configuration.
*/
private static final int DENSITY_DPI_UNDEFINED = 0;
private static final int DENSITY_DPI_LDPI = 120;
private static final int DENSITY_DPI_MDPI = 160;
private static final int DENSITY_DPI_TVDPI = 213;
private static final int DENSITY_DPI_HDPI = 240;
private static final int DENSITY_DPI_XHDPI = 320;
private static final int DENSITY_DPI_XXHDPI = 480;
private static final int DENSITY_DPI_XXXHDPI = 640;
private static final int DENSITY_DPI_ANY = 0xFFFE;
private static final int DENSITY_DPI_NONE = 0xFFFF;
private static final Map<Integer, String> DENSITY_DPI_VALUES =
ImmutableMap.<Integer, String>builder()
.put(DENSITY_DPI_UNDEFINED, "")
.put(DENSITY_DPI_LDPI, "ldpi")
.put(DENSITY_DPI_MDPI, "mdpi")
.put(DENSITY_DPI_TVDPI, "tvdpi")
.put(DENSITY_DPI_HDPI, "hdpi")
.put(DENSITY_DPI_XHDPI, "xhdpi")
.put(DENSITY_DPI_XXHDPI, "xxhdpi")
.put(DENSITY_DPI_XXXHDPI, "xxxhdpi")
.put(DENSITY_DPI_ANY, "anydpi")
.put(DENSITY_DPI_NONE, "nodpi")
.build();
private static final int KEYBOARD_NOKEYS = 1;
private static final int KEYBOARD_QWERTY = 2;
private static final int KEYBOARD_12KEY = 3;
private static final Map<Integer, String> KEYBOARD_VALUES = ImmutableMap.of(
KEYBOARD_NOKEYS, "nokeys",
KEYBOARD_QWERTY, "qwerty",
KEYBOARD_12KEY, "12key");
private static final int KEYBOARDHIDDEN_MASK = 0x03;
private static final int KEYBOARDHIDDEN_NO = 1;
private static final int KEYBOARDHIDDEN_YES = 2;
private static final int KEYBOARDHIDDEN_SOFT = 3;
private static final Map<Integer, String> KEYBOARDHIDDEN_VALUES = ImmutableMap.of(
KEYBOARDHIDDEN_NO, "keysexposed",
KEYBOARDHIDDEN_YES, "keyshidden",
KEYBOARDHIDDEN_SOFT, "keyssoft");
private static final int NAVIGATION_NONAV = 1;
private static final int NAVIGATION_DPAD = 2;
private static final int NAVIGATION_TRACKBALL = 3;
private static final int NAVIGATION_WHEEL = 4;
private static final Map<Integer, String> NAVIGATION_VALUES = ImmutableMap.of(
NAVIGATION_NONAV, "nonav",
NAVIGATION_DPAD, "dpad",
NAVIGATION_TRACKBALL, "trackball",
NAVIGATION_WHEEL, "wheel");
private static final int NAVIGATIONHIDDEN_MASK = 0x0C;
private static final int NAVIGATIONHIDDEN_NO = 0x04;
private static final int NAVIGATIONHIDDEN_YES = 0x08;
private static final Map<Integer, String> NAVIGATIONHIDDEN_VALUES = ImmutableMap.of(
NAVIGATIONHIDDEN_NO, "navexposed",
NAVIGATIONHIDDEN_YES, "navhidden");
private static final int ORIENTATION_PORTRAIT = 0x01;
private static final int ORIENTATION_LANDSCAPE = 0x02;
private static final Map<Integer, String> ORIENTATION_VALUES = ImmutableMap.of(
ORIENTATION_PORTRAIT, "port",
ORIENTATION_LANDSCAPE, "land");
private static final int SCREENLAYOUT_LAYOUTDIR_MASK = 0xC0;
private static final int SCREENLAYOUT_LAYOUTDIR_LTR = 0x40;
private static final int SCREENLAYOUT_LAYOUTDIR_RTL = 0x80;
private static final Map<Integer, String> SCREENLAYOUT_LAYOUTDIR_VALUES = ImmutableMap.of(
SCREENLAYOUT_LAYOUTDIR_LTR, "ldltr",
SCREENLAYOUT_LAYOUTDIR_RTL, "ldrtl");
private static final int SCREENLAYOUT_LONG_MASK = 0x30;
private static final int SCREENLAYOUT_LONG_NO = 0x10;
private static final int SCREENLAYOUT_LONG_YES = 0x20;
private static final Map<Integer, String> SCREENLAYOUT_LONG_VALUES = ImmutableMap.of(
SCREENLAYOUT_LONG_NO, "notlong",
SCREENLAYOUT_LONG_YES, "long");
private static final int SCREENLAYOUT_ROUND_MASK = 0x03;
private static final int SCREENLAYOUT_ROUND_NO = 0x01;
private static final int SCREENLAYOUT_ROUND_YES = 0x02;
private static final Map<Integer, String> SCREENLAYOUT_ROUND_VALUES = ImmutableMap.of(
SCREENLAYOUT_ROUND_NO, "notround",
SCREENLAYOUT_ROUND_YES, "round");
private static final int SCREENLAYOUT_SIZE_MASK = 0x0F;
private static final int SCREENLAYOUT_SIZE_SMALL = 0x01;
private static final int SCREENLAYOUT_SIZE_NORMAL = 0x02;
private static final int SCREENLAYOUT_SIZE_LARGE = 0x03;
private static final int SCREENLAYOUT_SIZE_XLARGE = 0x04;
private static final Map<Integer, String> SCREENLAYOUT_SIZE_VALUES = ImmutableMap.of(
SCREENLAYOUT_SIZE_SMALL, "small",
SCREENLAYOUT_SIZE_NORMAL, "normal",
SCREENLAYOUT_SIZE_LARGE, "large",
SCREENLAYOUT_SIZE_XLARGE, "xlarge");
private static final int TOUCHSCREEN_NOTOUCH = 1;
private static final int TOUCHSCREEN_FINGER = 3;
private static final Map<Integer, String> TOUCHSCREEN_VALUES = ImmutableMap.of(
TOUCHSCREEN_NOTOUCH, "notouch",
TOUCHSCREEN_FINGER, "finger");
private static final int UI_MODE_NIGHT_MASK = 0x30;
private static final int UI_MODE_NIGHT_NO = 0x10;
private static final int UI_MODE_NIGHT_YES = 0x20;
private static final Map<Integer, String> UI_MODE_NIGHT_VALUES = ImmutableMap.of(
UI_MODE_NIGHT_NO, "notnight",
UI_MODE_NIGHT_YES, "night");
private static final int UI_MODE_TYPE_MASK = 0x0F;
private static final int UI_MODE_TYPE_DESK = 0x02;
private static final int UI_MODE_TYPE_CAR = 0x03;
private static final int UI_MODE_TYPE_TELEVISION = 0x04;
private static final int UI_MODE_TYPE_APPLIANCE = 0x05;
private static final int UI_MODE_TYPE_WATCH = 0x06;
private static final int UI_MODE_TYPE_VR_HEADSET = 0x07;
// start - miui
private static final int UI_MODE_TYPE_GODZILLAUI = 0x0b;
private static final int UI_MODE_TYPE_SMALLUI = 0x0c;
private static final int UI_MODE_TYPE_MEDIUMUI = 0x0d;
private static final int UI_MODE_TYPE_LARGEUI = 0x0e;
private static final int UI_MODE_TYPE_HUGEUI = 0x0f;
// end - miui
private static final Map<Integer, String> UI_MODE_TYPE_VALUES =
ImmutableMap.<Integer, String>builder()
.put(UI_MODE_TYPE_DESK, "desk")
.put(UI_MODE_TYPE_CAR, "car")
.put(UI_MODE_TYPE_TELEVISION, "television")
.put(UI_MODE_TYPE_APPLIANCE, "appliance")
.put(UI_MODE_TYPE_WATCH, "watch")
.put(UI_MODE_TYPE_VR_HEADSET, "vrheadset")
.put(UI_MODE_TYPE_GODZILLAUI, "godzillaui")
.put(UI_MODE_TYPE_SMALLUI, "smallui")
.put(UI_MODE_TYPE_MEDIUMUI, "mediumui")
.put(UI_MODE_TYPE_LARGEUI, "largeui")
.put(UI_MODE_TYPE_HUGEUI, "hugeui").build();
/**
* The minimum size in bytes that this configuration must be to contain screen config info.
*/
private static final int SCREEN_CONFIG_MIN_SIZE = 32;
/**
* The minimum size in bytes that this configuration must be to contain screen dp info.
*/
private static final int SCREEN_DP_MIN_SIZE = 36;
/**
* The minimum size in bytes that this configuration must be to contain locale info.
*/
private static final int LOCALE_MIN_SIZE = 48;
/**
* The minimum size in bytes that this config must be to contain the screenConfig extension.
*/
private static final int SCREEN_CONFIG_EXTENSION_MIN_SIZE = 52;
/** /**
* The number of bytes that this resource configuration takes up. * The number of bytes that this resource configuration takes up.
*/ */
@@ -662,7 +708,7 @@ public class BinaryResourceConfiguration implements SerializableResource {
Map<Type, String> result = new LinkedHashMap<>(); // Preserve order for #toString(). Map<Type, String> result = new LinkedHashMap<>(); // Preserve order for #toString().
result.put(Type.MCC, mcc() != 0 ? "mcc" + mcc() : ""); result.put(Type.MCC, mcc() != 0 ? "mcc" + mcc() : "");
result.put(Type.MNC, mnc() != 0 ? "mnc" + mnc() : ""); result.put(Type.MNC, mnc() != 0 ? "mnc" + mnc() : "");
result.put(Type.LANGUAGE_STRING, !languageString().isEmpty() ? languageString() : ""); result.put(Type.LANGUAGE_STRING, !languageString().isEmpty() ? "" + languageString() : "");
result.put(Type.REGION_STRING, !regionString().isEmpty() ? "r" + regionString() : ""); result.put(Type.REGION_STRING, !regionString().isEmpty() ? "r" + regionString() : "");
result.put(Type.SCREEN_LAYOUT_DIRECTION, result.put(Type.SCREEN_LAYOUT_DIRECTION,
getOrDefault(SCREENLAYOUT_LAYOUTDIR_VALUES, screenLayoutDirection(), "")); getOrDefault(SCREENLAYOUT_LAYOUTDIR_VALUES, screenLayoutDirection(), ""));
@@ -696,31 +742,4 @@ public class BinaryResourceConfiguration implements SerializableResource {
V value = map.get(key); V value = map.get(key);
return value != null ? value : defaultValue; return value != null ? value : defaultValue;
} }
/**
* The different types of configs that can be present in a {@link BinaryResourceConfiguration}.
*/
public enum Type {
MCC,
MNC,
LANGUAGE_STRING,
REGION_STRING,
SCREEN_LAYOUT_DIRECTION,
SMALLEST_SCREEN_WIDTH_DP,
SCREEN_WIDTH_DP,
SCREEN_HEIGHT_DP,
SCREEN_LAYOUT_SIZE,
SCREEN_LAYOUT_LONG,
SCREEN_LAYOUT_ROUND,
ORIENTATION,
UI_MODE_TYPE,
UI_MODE_NIGHT,
DENSITY_DPI,
TOUCHSCREEN,
KEYBOARD_HIDDEN,
KEYBOARD,
NAVIGATION_HIDDEN,
NAVIGATION,
SDK_VERSION
}
} }
@@ -27,14 +27,10 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
/** /** Given an arsc file, maps the contents of the file. */
* Given an arsc file, maps the contents of the file.
*/
public final class BinaryResourceFile implements SerializableResource { public final class BinaryResourceFile implements SerializableResource {
/** /** The chunks contained in this resource file. */
* The chunks contained in this resource file.
*/
private final List<Chunk> chunks = new ArrayList<>(); private final List<Chunk> chunks = new ArrayList<>();
public BinaryResourceFile(byte[] buf) { public BinaryResourceFile(byte[] buf) {
@@ -57,9 +53,7 @@ public final class BinaryResourceFile implements SerializableResource {
return new BinaryResourceFile(buf); return new BinaryResourceFile(buf);
} }
/** /** Returns the chunks in this resource file. */
* Returns the chunks in this resource file.
*/
public List<Chunk> getChunks() { public List<Chunk> getChunks() {
return Collections.unmodifiableList(chunks); return Collections.unmodifiableList(chunks);
} }
@@ -27,21 +27,15 @@ import java.util.Objects;
*/ */
public class BinaryResourceIdentifier { public class BinaryResourceIdentifier {
/** /** The {@link PackageChunk} id mask for a packed resource id of the form 0xpptteeee. */
* The {@link PackageChunk} id mask for a packed resource id of the form 0xpptteeee.
*/
private static final int PACKAGE_ID_MASK = 0xFF000000; private static final int PACKAGE_ID_MASK = 0xFF000000;
private static final int PACKAGE_ID_SHIFT = 24; private static final int PACKAGE_ID_SHIFT = 24;
/** /** The {@link TypeChunk} id mask for a packed resource id of the form 0xpptteeee. */
* The {@link TypeChunk} id mask for a packed resource id of the form 0xpptteeee.
*/
private static final int TYPE_ID_MASK = 0x00FF0000; private static final int TYPE_ID_MASK = 0x00FF0000;
private static final int TYPE_ID_SHIFT = 16; private static final int TYPE_ID_SHIFT = 16;
/** /** The {@link TypeChunk.Entry} id mask for a packed resource id of the form 0xpptteeee. */
* The {@link TypeChunk.Entry} id mask for a packed resource id of the form 0xpptteeee.
*/
private static final int ENTRY_ID_MASK = 0xFFFF; private static final int ENTRY_ID_MASK = 0xFFFF;
private static final int ENTRY_ID_SHIFT = 0; private static final int ENTRY_ID_SHIFT = 0;
@@ -49,15 +43,7 @@ public class BinaryResourceIdentifier {
private final int typeId; private final int typeId;
private final int entryId; private final int entryId;
private BinaryResourceIdentifier(int packageId, int typeId, int entryId) { /** Returns a {@link BinaryResourceIdentifier} from a {@code resourceId} of the form 0xpptteeee. */
this.packageId = packageId;
this.typeId = typeId;
this.entryId = entryId;
}
/**
* Returns a {@link BinaryResourceIdentifier} from a {@code resourceId} of the form 0xpptteeee.
*/
public static BinaryResourceIdentifier create(int resourceId) { public static BinaryResourceIdentifier create(int resourceId) {
int packageId = (resourceId & PACKAGE_ID_MASK) >>> PACKAGE_ID_SHIFT; int packageId = (resourceId & PACKAGE_ID_MASK) >>> PACKAGE_ID_SHIFT;
int typeId = (resourceId & TYPE_ID_MASK) >>> TYPE_ID_SHIFT; int typeId = (resourceId & TYPE_ID_MASK) >>> TYPE_ID_SHIFT;
@@ -65,9 +51,7 @@ public class BinaryResourceIdentifier {
return create(packageId, typeId, entryId); return create(packageId, typeId, entryId);
} }
/** /** Returns a {@link BinaryResourceIdentifier} with the given identifiers. */
* Returns a {@link BinaryResourceIdentifier} with the given identifiers.
*/
public static BinaryResourceIdentifier create(int packageId, int typeId, int entryId) { public static BinaryResourceIdentifier create(int packageId, int typeId, int entryId) {
Preconditions.checkState((packageId & 0xFF) == packageId, "packageId must be <= 0xFF."); Preconditions.checkState((packageId & 0xFF) == packageId, "packageId must be <= 0xFF.");
Preconditions.checkState((typeId & 0xFF) == typeId, "typeId must be <= 0xFF."); Preconditions.checkState((typeId & 0xFF) == typeId, "typeId must be <= 0xFF.");
@@ -75,36 +59,28 @@ public class BinaryResourceIdentifier {
return new BinaryResourceIdentifier(packageId, typeId, entryId); return new BinaryResourceIdentifier(packageId, typeId, entryId);
} }
/** private BinaryResourceIdentifier(int packageId, int typeId, int entryId) {
* The (1-based) id of the {@link PackageChunk} containing this resource. this.packageId = packageId;
*/ this.typeId = typeId;
public int packageId() { this.entryId = entryId;
return packageId;
} }
/** /** The (1-based) id of the {@link PackageChunk} containing this resource. */
* The (1-based) id of the {@link TypeChunk} containing this resource. public int packageId() { return packageId; }
*/
public int typeId() {
return typeId;
}
/** /** The (1-based) id of the {@link TypeChunk} containing this resource. */
* The (0-based) index of the entry in a {@link TypeChunk} containing this resource. public int typeId() { return typeId; }
*/
public int entryId() {
return entryId;
}
public int resId() { /** The (0-based) index of the entry in a {@link TypeChunk} containing this resource. */
return packageId << PACKAGE_ID_SHIFT | typeId << TYPE_ID_SHIFT | entryId; public int entryId() { return entryId; }
}
public int resId() { return packageId << PACKAGE_ID_SHIFT | typeId << TYPE_ID_SHIFT | entryId; }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
BinaryResourceIdentifier that = (BinaryResourceIdentifier) o; BinaryResourceIdentifier that = (BinaryResourceIdentifier)o;
return packageId == that.packageId && return packageId == that.packageId &&
typeId == that.typeId && typeId == that.typeId &&
entryId == that.entryId; entryId == that.entryId;
@@ -26,13 +26,26 @@ import java.nio.charset.Charset;
import static java.nio.charset.StandardCharsets.UTF_16LE; import static java.nio.charset.StandardCharsets.UTF_16LE;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
/** /** Provides utilities to decode/encode a String packed in an arsc resource file. */
* Provides utilities to decode/encode a String packed in an arsc resource file.
*/
public final class BinaryResourceString { public final class BinaryResourceString {
private BinaryResourceString() { /** Type of {@link BinaryResourceString} to encode / decode. */
} // Private constructor public enum Type {
UTF8(UTF_8),
UTF16(UTF_16LE);
private final Charset charset;
Type(Charset charset) {
this.charset = charset;
}
public Charset charset() {
return charset;
}
}
private BinaryResourceString() {} // Private constructor
/** /**
* Given a buffer and an offset into the buffer, returns a String. The {@code offset} is the * Given a buffer and an offset into the buffer, returns a String. The {@code offset} is the
@@ -148,22 +161,4 @@ public final class BinaryResourceString {
} }
return length; return length;
} }
/**
* Type of {@link BinaryResourceString} to encode / decode.
*/
public enum Type {
UTF8(UTF_8),
UTF16(UTF_16LE);
private final Charset charset;
Type(Charset charset) {
this.charset = charset;
}
public Charset charset() {
return charset;
}
}
} }
@@ -26,23 +26,75 @@ import java.nio.ByteOrder;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
/** /** Represents a single typed resource value. */
* Represents a single typed resource value.
*/
public class BinaryResourceValue implements SerializableResource { public class BinaryResourceValue implements SerializableResource {
/** /** Resource type codes. */
* The serialized size in bytes of a {@link BinaryResourceValue}. public enum Type {
*/ /** {@code data} is either 0 (undefined) or 1 (empty). */
public static final int SIZE = 8; NULL(0x00),
public int size; /** {@code data} holds a {@link ResourceTableChunk} entry reference. */
public Type type; REFERENCE(0x01),
public int data; /** {@code data} holds an attribute resource identifier. */
public BinaryResourceValue(int size, Type type, int data) { ATTRIBUTE(0x02),
this.size = size; /** {@code data} holds an index into the containing resource table's string pool. */
this.type = type; STRING(0x03),
this.data = data; /** {@code data} holds a single-precision floating point number. */
FLOAT(0x04),
/** {@code data} holds a complex number encoding a dimension value, such as "100in". */
DIMENSION(0x05),
/** {@code data} holds a complex number encoding a fraction of a container. */
FRACTION(0x06),
/** {@code data} holds a dynamic {@link ResourceTableChunk} entry reference. */
DYNAMIC_REFERENCE(0x07),
/** {@code data} holds a dynamic attribute resource identifier. */
DYNAMIC_ATTRIBUTE(0x08),
/** {@code data} is a raw integer value of the form n..n. */
INT_DEC(0x10),
/** {@code data} is a raw integer value of the form 0xn..n. */
INT_HEX(0x11),
/** {@code data} is either 0 (false) or 1 (true). */
INT_BOOLEAN(0x12),
/** {@code data} is a raw integer value of the form #aarrggbb. */
INT_COLOR_ARGB8(0x1c),
/** {@code data} is a raw integer value of the form #rrggbb. */
INT_COLOR_RGB8(0x1d),
/** {@code data} is a raw integer value of the form #argb. */
INT_COLOR_ARGB4(0x1e),
/** {@code data} is a raw integer value of the form #rgb. */
INT_COLOR_RGB4(0x1f);
private final byte code;
private static final Map<Byte, Type> FROM_BYTE;
static {
Builder<Byte, Type> builder = ImmutableMap.builder();
for (Type type : values()) {
builder.put(type.code(), type);
} }
FROM_BYTE = builder.build();
}
Type(int code) {
this.code = UnsignedBytes.checkedCast(code);
}
public byte code() {
return code;
}
public static Type fromCode(byte code) {
return Preconditions.checkNotNull(FROM_BYTE.get(code), "Unknown resource type: %s", code);
}
}
/** The serialized size in bytes of a {@link BinaryResourceValue}. */
public static final int SIZE = 8;
private final int size;
private final Type type;
private final int data;
public static BinaryResourceValue create(ByteBuffer buffer) { public static BinaryResourceValue create(ByteBuffer buffer) {
int size = (buffer.getShort() & 0xFFFF); int size = (buffer.getShort() & 0xFFFF);
@@ -52,26 +104,20 @@ public class BinaryResourceValue implements SerializableResource {
return new BinaryResourceValue(size, type, data); return new BinaryResourceValue(size, type, data);
} }
/** public BinaryResourceValue(int size, Type type, int data) {
* The length in bytes of this value. this.size = size;
*/ this.type = type;
public int size() { this.data = data;
return size;
} }
/** /** The length in bytes of this value. */
* The raw data type of this value. public int size() { return size; }
*/
public Type type() {
return type;
}
/** /** The raw data type of this value. */
* The actual 4-byte value; interpretation of the value depends on {@code dataType}. public Type type() { return type; }
*/
public int data() { /** The actual 4-byte value; interpretation of the value depends on {@code dataType}. */
return data; public int data() { return data; }
}
@Override @Override
public byte[] toByteArray() { public byte[] toByteArray() {
@@ -92,7 +138,7 @@ public class BinaryResourceValue implements SerializableResource {
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
BinaryResourceValue that = (BinaryResourceValue) o; BinaryResourceValue that = (BinaryResourceValue)o;
return size == that.size && return size == that.size &&
data == that.data && data == that.data &&
type == that.type; type == that.type;
@@ -102,98 +148,4 @@ public class BinaryResourceValue implements SerializableResource {
public int hashCode() { public int hashCode() {
return Objects.hash(size, type, data); return Objects.hash(size, type, data);
} }
/**
* Resource type codes.
*/
public enum Type {
/**
* {@code data} is either 0 (undefined) or 1 (empty).
*/
NULL(0x00),
/**
* {@code data} holds a {@link ResourceTableChunk} entry reference.
*/
REFERENCE(0x01),
/**
* {@code data} holds an attribute resource identifier.
*/
ATTRIBUTE(0x02),
/**
* {@code data} holds an index into the containing resource table's string pool.
*/
STRING(0x03),
/**
* {@code data} holds a single-precision floating point number.
*/
FLOAT(0x04),
/**
* {@code data} holds a complex number encoding a dimension value, such as "100in".
*/
DIMENSION(0x05),
/**
* {@code data} holds a complex number encoding a fraction of a container.
*/
FRACTION(0x06),
/**
* {@code data} holds a dynamic {@link ResourceTableChunk} entry reference.
*/
DYNAMIC_REFERENCE(0x07),
/**
* {@code data} holds a dynamic attribute resource identifier.
*/
DYNAMIC_ATTRIBUTE(0x08),
/**
* {@code data} is a raw integer value of the form n..n.
*/
INT_DEC(0x10),
/**
* {@code data} is a raw integer value of the form 0xn..n.
*/
INT_HEX(0x11),
/**
* {@code data} is either 0 (false) or 1 (true).
*/
INT_BOOLEAN(0x12),
/**
* {@code data} is a raw integer value of the form #aarrggbb.
*/
INT_COLOR_ARGB8(0x1c),
/**
* {@code data} is a raw integer value of the form #rrggbb.
*/
INT_COLOR_RGB8(0x1d),
/**
* {@code data} is a raw integer value of the form #argb.
*/
INT_COLOR_ARGB4(0x1e),
/**
* {@code data} is a raw integer value of the form #rgb.
*/
INT_COLOR_RGB4(0x1f);
private static final Map<Byte, Type> FROM_BYTE;
static {
Builder<Byte, Type> builder = ImmutableMap.builder();
for (Type type : values()) {
builder.put(type.code(), type);
}
FROM_BYTE = builder.build();
}
private final byte code;
Type(int code) {
this.code = UnsignedBytes.checkedCast(code);
}
public static Type fromCode(byte code) {
return Preconditions.checkNotNull(FROM_BYTE.get(code), "Unknown resource type: %s", code);
}
public byte code() {
return code;
}
}
} }
@@ -30,41 +30,73 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.Map; import java.util.Map;
/** /** Represents a generic chunk. */
* Represents a generic chunk.
*/
public abstract class Chunk implements SerializableResource { public abstract class Chunk implements SerializableResource {
/** /** Types of chunks that can exist. */
* The byte boundary to pad chunks on. public enum Type {
*/ NULL(0x0000),
STRING_POOL(0x0001),
TABLE(0x0002),
XML(0x0003),
XML_START_NAMESPACE(0x0100),
XML_END_NAMESPACE(0x0101),
XML_START_ELEMENT(0x0102),
XML_END_ELEMENT(0x0103),
XML_CDATA(0x0104),
XML_RESOURCE_MAP(0x0180),
TABLE_PACKAGE(0x0200),
TABLE_TYPE(0x0201),
TABLE_TYPE_SPEC(0x0202),
TABLE_LIBRARY(0x0203);
private final short code;
private static final Map<Short, Type> FROM_SHORT;
static {
Builder<Short, Type> builder = ImmutableMap.builder();
for (Type type : values()) {
builder.put(type.code(), type);
}
FROM_SHORT = builder.build();
}
Type(int code) {
this.code = Shorts.checkedCast(code);
}
public short code() {
return code;
}
public static Type fromCode(short code) {
return Preconditions.checkNotNull(FROM_SHORT.get(code), "Unknown chunk type: %s", code);
}
}
/** The byte boundary to pad chunks on. */
public static final int PAD_BOUNDARY = 4; public static final int PAD_BOUNDARY = 4;
/**
* The number of bytes in every chunk that describes chunk type, header size, and chunk size. /** The number of bytes in every chunk that describes chunk type, header size, and chunk size. */
*/
public static final int METADATA_SIZE = 8; public static final int METADATA_SIZE = 8;
/**
* The offset in bytes, from the start of the chunk, where the chunk size can be found. /** The offset in bytes, from the start of the chunk, where the chunk size can be found. */
*/
private static final int CHUNK_SIZE_OFFSET = 4; private static final int CHUNK_SIZE_OFFSET = 4;
/**
* Size of the chunk header in bytes. /** The parent to this chunk, if any. */
*/
protected final int headerSize;
/**
* headerSize + dataSize. The total size of this chunk.
*/
protected final int chunkSize;
/**
* Offset of this chunk from the start of the file.
*/
protected final int offset;
/**
* The parent to this chunk, if any.
*/
@Nullable @Nullable
private final Chunk parent; private final Chunk parent;
/** Size of the chunk header in bytes. */
protected final int headerSize;
/** headerSize + dataSize. The total size of this chunk. */
protected final int chunkSize;
/** Offset of this chunk from the start of the file. */
protected final int offset;
protected Chunk(ByteBuffer buffer, @Nullable Chunk parent) { protected Chunk(ByteBuffer buffer, @Nullable Chunk parent) {
this.parent = parent; this.parent = parent;
offset = buffer.position() - 2; offset = buffer.position() - 2;
@@ -72,6 +104,133 @@ public abstract class Chunk implements SerializableResource {
chunkSize = buffer.getInt(); chunkSize = buffer.getInt();
} }
/**
* Finishes initialization of a chunk. This should be called immediately after the constructor.
* This is separate from the constructor so that the header of a chunk can be fully initialized
* before the payload of that chunk is initialized for chunks that require such behavior.
*
* @param buffer The buffer that the payload will be initialized from.
*/
protected void init(ByteBuffer buffer) {}
/**
* Returns the parent to this chunk, if any. A parent is a chunk whose payload contains this
* chunk. If there's no parent, null is returned.
*/
@Nullable
public Chunk getParent() {
return parent;
}
protected abstract Type getType();
/** Returns the size of this chunk's header. */
public final int getHeaderSize() {
return headerSize;
}
/**
* Returns the size of this chunk when it was first read from a buffer. A chunk's size can deviate
* from this value when its data is modified (e.g. adding an entry, changing a string).
*
* <p>A chunk's current size can be determined from the length of the byte array returned from
* {@link #toByteArray}.
*/
public final int getOriginalChunkSize() {
return chunkSize;
}
/**
* Reposition the buffer after this chunk. Use this at the end of a Chunk constructor.
* @param buffer The buffer to be repositioned.
*/
private final void seekToEndOfChunk(ByteBuffer buffer) {
buffer.position(offset + chunkSize);
}
/**
* Writes the type and header size. We don't know how big this chunk will be (it could be
* different since the last time we checked), so this needs to be passed in.
*
* @param output The buffer that will be written to.
* @param chunkSize The total size of this chunk in bytes, including the header.
*/
protected final void writeHeader(ByteBuffer output, int chunkSize) {
int start = output.position();
output.putShort(getType().code());
output.putShort((short) headerSize);
output.putInt(chunkSize);
writeHeader(output);
int headerBytes = output.position() - start;
Preconditions.checkState(headerBytes == getHeaderSize(),
"Written header is wrong size. Got %s, want %s", headerBytes, getHeaderSize());
}
/**
* Writes the remaining header (after the type, {@code headerSize}, and {@code chunkSize}).
*
* @param output The buffer that the header will be written to.
*/
protected void writeHeader(ByteBuffer output) {}
/**
* Writes the chunk payload. The payload is data in a chunk which is not in
* the first {@code headerSize} bytes of the chunk.
*
* @param output The stream that the payload will be written to.
* @param header The already-written header. This can be modified to fix payload offsets.
* @param shrink True if this payload should be optimized for size.
* @throws IOException Thrown if {@code output} could not be written to (out of memory).
*/
protected void writePayload(DataOutput output, ByteBuffer header, boolean shrink)
throws IOException {}
/**
* Pads {@code output} until {@code currentLength} is on a 4-byte boundary.
*
* @param output The {@link DataOutput} that will be padded.
* @param currentLength The current length, in bytes, of {@code output}
* @return The new length of {@code output}
* @throws IOException Thrown if {@code output} could not be written to.
*/
protected int writePad(DataOutput output, int currentLength) throws IOException {
while (currentLength % PAD_BOUNDARY != 0) {
output.write(0);
++currentLength;
}
return currentLength;
}
@Override
public final byte[] toByteArray() throws IOException {
return toByteArray(false);
}
/**
* Converts this chunk into an array of bytes representation. Normally you will not need to
* override this method unless your header changes based on the contents / size of the payload.
*/
@Override
public final byte[] toByteArray(boolean shrink) throws IOException {
ByteBuffer header = ByteBuffer.allocate(getHeaderSize()).order(ByteOrder.LITTLE_ENDIAN);
writeHeader(header, 0); // The chunk size isn't known yet. This will be filled in later.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (LittleEndianDataOutputStream payload = new LittleEndianDataOutputStream(baos)) {
writePayload(payload, header, shrink);
}
byte[] payloadBytes = baos.toByteArray();
int chunkSize = getHeaderSize() + payloadBytes.length;
header.putInt(CHUNK_SIZE_OFFSET, chunkSize);
// Combine results
ByteBuffer result = ByteBuffer.allocate(chunkSize).order(ByteOrder.LITTLE_ENDIAN);
result.put(header.array());
result.put(payloadBytes);
return result.array();
}
/** /**
* Creates a new chunk whose contents start at {@code buffer}'s current position. * Creates a new chunk whose contents start at {@code buffer}'s current position.
* *
@@ -139,181 +298,4 @@ public abstract class Chunk implements SerializableResource {
result.seekToEndOfChunk(buffer); result.seekToEndOfChunk(buffer);
return result; return result;
} }
/**
* Finishes initialization of a chunk. This should be called immediately after the constructor.
* This is separate from the constructor so that the header of a chunk can be fully initialized
* before the payload of that chunk is initialized for chunks that require such behavior.
*
* @param buffer The buffer that the payload will be initialized from.
*/
protected void init(ByteBuffer buffer) {
}
/**
* Returns the parent to this chunk, if any. A parent is a chunk whose payload contains this
* chunk. If there's no parent, null is returned.
*/
@Nullable
public Chunk getParent() {
return parent;
}
protected abstract Type getType();
/**
* Returns the size of this chunk's header.
*/
public final int getHeaderSize() {
return headerSize;
}
/**
* Returns the size of this chunk when it was first read from a buffer. A chunk's size can deviate
* from this value when its data is modified (e.g. adding an entry, changing a string).
*
* <p>A chunk's current size can be determined from the length of the byte array returned from
* {@link #toByteArray}.
*/
public final int getOriginalChunkSize() {
return chunkSize;
}
/**
* Reposition the buffer after this chunk. Use this at the end of a Chunk constructor.
*
* @param buffer The buffer to be repositioned.
*/
private final void seekToEndOfChunk(ByteBuffer buffer) {
buffer.position(offset + chunkSize);
}
/**
* Writes the type and header size. We don't know how big this chunk will be (it could be
* different since the last time we checked), so this needs to be passed in.
*
* @param output The buffer that will be written to.
* @param chunkSize The total size of this chunk in bytes, including the header.
*/
protected final void writeHeader(ByteBuffer output, int chunkSize) {
int start = output.position();
output.putShort(getType().code());
output.putShort((short) headerSize);
output.putInt(chunkSize);
writeHeader(output);
int headerBytes = output.position() - start;
Preconditions.checkState(headerBytes == getHeaderSize(),
"Written header is wrong size. Got %s, want %s", headerBytes, getHeaderSize());
}
/**
* Writes the remaining header (after the type, {@code headerSize}, and {@code chunkSize}).
*
* @param output The buffer that the header will be written to.
*/
protected void writeHeader(ByteBuffer output) {
}
/**
* Writes the chunk payload. The payload is data in a chunk which is not in
* the first {@code headerSize} bytes of the chunk.
*
* @param output The stream that the payload will be written to.
* @param header The already-written header. This can be modified to fix payload offsets.
* @param shrink True if this payload should be optimized for size.
* @throws IOException Thrown if {@code output} could not be written to (out of memory).
*/
protected void writePayload(DataOutput output, ByteBuffer header, boolean shrink)
throws IOException {
}
/**
* Pads {@code output} until {@code currentLength} is on a 4-byte boundary.
*
* @param output The {@link DataOutput} that will be padded.
* @param currentLength The current length, in bytes, of {@code output}
* @return The new length of {@code output}
* @throws IOException Thrown if {@code output} could not be written to.
*/
protected int writePad(DataOutput output, int currentLength) throws IOException {
while (currentLength % PAD_BOUNDARY != 0) {
output.write(0);
++currentLength;
}
return currentLength;
}
@Override
public final byte[] toByteArray() throws IOException {
return toByteArray(false);
}
/**
* Converts this chunk into an array of bytes representation. Normally you will not need to
* override this method unless your header changes based on the contents / size of the payload.
*/
@Override
public final byte[] toByteArray(boolean shrink) throws IOException {
ByteBuffer header = ByteBuffer.allocate(getHeaderSize()).order(ByteOrder.LITTLE_ENDIAN);
writeHeader(header, 0); // The chunk size isn't known yet. This will be filled in later.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (LittleEndianDataOutputStream payload = new LittleEndianDataOutputStream(baos)) {
writePayload(payload, header, shrink);
}
byte[] payloadBytes = baos.toByteArray();
int chunkSize = getHeaderSize() + payloadBytes.length;
header.putInt(CHUNK_SIZE_OFFSET, chunkSize);
// Combine results
ByteBuffer result = ByteBuffer.allocate(chunkSize).order(ByteOrder.LITTLE_ENDIAN);
result.put(header.array());
result.put(payloadBytes);
return result.array();
}
/**
* Types of chunks that can exist.
*/
public enum Type {
NULL(0x0000),
STRING_POOL(0x0001),
TABLE(0x0002),
XML(0x0003),
XML_START_NAMESPACE(0x0100),
XML_END_NAMESPACE(0x0101),
XML_START_ELEMENT(0x0102),
XML_END_ELEMENT(0x0103),
XML_CDATA(0x0104),
XML_RESOURCE_MAP(0x0180),
TABLE_PACKAGE(0x0200),
TABLE_TYPE(0x0201),
TABLE_TYPE_SPEC(0x0202),
TABLE_LIBRARY(0x0203);
private static final Map<Short, Type> FROM_SHORT;
static {
Builder<Short, Type> builder = ImmutableMap.builder();
for (Type type : values()) {
builder.put(type.code(), type);
}
FROM_SHORT = builder.build();
}
private final short code;
Type(int code) {
this.code = Shorts.checkedCast(code);
}
public static Type fromCode(short code) {
return Preconditions.checkNotNull(FROM_SHORT.get(code), "Unknown chunk type: %s", code);
}
public short code() {
return code;
}
}
} }
@@ -24,9 +24,7 @@ import java.nio.ByteBuffer;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
/** /** Represents a chunk whose payload is a list of sub-chunks. */
* Represents a chunk whose payload is a list of sub-chunks.
*/
public abstract class ChunkWithChunks extends Chunk { public abstract class ChunkWithChunks extends Chunk {
private final Map<Integer, Chunk> chunks = new LinkedHashMap<>(); private final Map<Integer, Chunk> chunks = new LinkedHashMap<>();
@@ -17,7 +17,6 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -33,17 +32,13 @@ import java.util.Objects;
*/ */
public final class LibraryChunk extends Chunk { public final class LibraryChunk extends Chunk {
/** /** The number of resources of this type at creation time. */
* The number of resources of this type at creation time.
*/
private final int entryCount; private final int entryCount;
/** /** The libraries used in this chunk (package id + name). */
* The libraries used in this chunk (package id + name).
*/
private final List<Entry> entries = new ArrayList<>(); private final List<Entry> entries = new ArrayList<>();
LibraryChunk(ByteBuffer buffer, @Nullable Chunk parent) { protected LibraryChunk(ByteBuffer buffer, @Nullable Chunk parent) {
super(buffer, parent); super(buffer, parent);
entryCount = buffer.getInt(); entryCount = buffer.getInt();
} }
@@ -85,43 +80,31 @@ public final class LibraryChunk extends Chunk {
} }
} }
/** /** A shared library package-id to package name entry. */
* A shared library package-id to package name entry.
*/
protected static class Entry implements SerializableResource { protected static class Entry implements SerializableResource {
/** /** Library entries only contain a package ID (4 bytes) and a package name. */
* Library entries only contain a package ID (4 bytes) and a package name.
*/
private static final int SIZE = 4 + PackageUtils.PACKAGE_NAME_SIZE; private static final int SIZE = 4 + PackageUtils.PACKAGE_NAME_SIZE;
private final int packageId; private final int packageId;
private final String packageName; private final String packageName;
private Entry(int packageId, String packageName) {
this.packageId = packageId;
this.packageName = packageName;
}
static Entry create(ByteBuffer buffer, int offset) { static Entry create(ByteBuffer buffer, int offset) {
int packageId = buffer.getInt(offset); int packageId = buffer.getInt(offset);
String packageName = PackageUtils.readPackageName(buffer, offset + 4); String packageName = PackageUtils.readPackageName(buffer, offset + 4);
return new Entry(packageId, packageName); return new Entry(packageId, packageName);
} }
/** private Entry(int packageId, String packageName) {
* The id assigned to the shared library at build time. this.packageId = packageId;
*/ this.packageName = packageName;
public int packageId() {
return packageId;
} }
/** /** The id assigned to the shared library at build time. */
* The package name of the shared library. public int packageId() { return packageId; }
*/
public String packageName() { /** The package name of the shared library. */
return packageName; public String packageName() { return packageName; }
}
@Override @Override
public byte[] toByteArray() throws IOException { public byte[] toByteArray() throws IOException {
@@ -140,7 +123,7 @@ public final class LibraryChunk extends Chunk {
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
Entry entry = (Entry) o; Entry entry = (Entry)o;
return packageId == entry.packageId && return packageId == entry.packageId &&
Objects.equals(packageName, entry.packageName); Objects.equals(packageName, entry.packageName);
} }
@@ -16,11 +16,11 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import androidx.annotation.Nullable;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -29,62 +29,46 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
/** /** A package chunk is a collection of resource data types within a package. */
* A package chunk is a collection of resource data types within a package.
*/
public final class PackageChunk extends ChunkWithChunks { public final class PackageChunk extends ChunkWithChunks {
/** /** Offset in bytes, from the start of the chunk, where {@code typeStringsOffset} can be found. */
* Offset in bytes, from the start of the chunk, where {@code typeStringsOffset} can be found.
*/
private static final int TYPE_OFFSET_OFFSET = 268; private static final int TYPE_OFFSET_OFFSET = 268;
/** /** Offset in bytes, from the start of the chunk, where {@code keyStringsOffset} can be found. */
* Offset in bytes, from the start of the chunk, where {@code keyStringsOffset} can be found.
*/
private static final int KEY_OFFSET_OFFSET = 276; private static final int KEY_OFFSET_OFFSET = 276;
/**
* The offset (from {@code offset}) in the original buffer where type strings start. /** The package id if this is a base package, or 0 if not a base package. */
*/
private final int typeStringsOffset;
/**
* The index into the type string pool of the last public type.
*/
private final int lastPublicType;
/**
* An offset to the string pool that contains the key strings for this package.
*/
private final int keyStringsOffset;
/**
* The index into the key string pool of the last public key.
*/
private final int lastPublicKey;
/**
* An offset to the type ID(s). This is undocumented in the original code.
*/
private final int typeIdOffset;
/**
* Contains a mapping of a type index to its {@link TypeSpecChunk}.
*/
private final Map<Integer, TypeSpecChunk> typeSpecs = new HashMap<>();
/**
* Contains a mapping of a type index to all of the {@link TypeChunk} with that index.
*/
private final Multimap<Integer, TypeChunk> types = ArrayListMultimap.create();
/**
* The package id if this is a base package, or 0 if not a base package.
*/
private int id; private int id;
/**
* The name of the package. /** The name of the package. */
*/
private String packageName; private String packageName;
/**
* May contain a library chunk for mapping dynamic references to resolved references. /** The offset (from {@code offset}) in the original buffer where type strings start. */
*/ private final int typeStringsOffset;
/** The index into the type string pool of the last public type. */
private final int lastPublicType;
/** An offset to the string pool that contains the key strings for this package. */
private final int keyStringsOffset;
/** The index into the key string pool of the last public key. */
private final int lastPublicKey;
/** An offset to the type ID(s). This is undocumented in the original code. */
private final int typeIdOffset;
/** Contains a mapping of a type index to its {@link TypeSpecChunk}. */
private final Map<Integer, TypeSpecChunk> typeSpecs = new HashMap<>();
/** Contains a mapping of a type index to all of the {@link TypeChunk} with that index. */
private final Multimap<Integer, TypeChunk> types = ArrayListMultimap.create();
/** May contain a library chunk for mapping dynamic references to resolved references. */
private Optional<LibraryChunk> libraryChunk = Optional.empty(); private Optional<LibraryChunk> libraryChunk = Optional.empty();
PackageChunk(ByteBuffer buffer, @Nullable Chunk parent) { protected PackageChunk(ByteBuffer buffer, @Nullable Chunk parent) {
super(buffer, parent); super(buffer, parent);
id = buffer.getInt(); id = buffer.getInt();
packageName = PackageUtils.readPackageName(buffer, buffer.position()); packageName = PackageUtils.readPackageName(buffer, buffer.position());
@@ -118,16 +102,12 @@ public final class PackageChunk extends ChunkWithChunks {
} }
} }
/** /** Returns the package id if this is a base package, or 0 if not a base package. */
* Returns the package id if this is a base package, or 0 if not a base package.
*/
public int getId() { public int getId() {
return id; return id;
} }
/** /** Sets the package id */
* Sets the package id
*/
public void setId(int id) { public void setId(int id) {
this.id = id; this.id = id;
} }
@@ -164,9 +144,7 @@ public final class PackageChunk extends ChunkWithChunks {
return (StringPoolChunk) chunk; return (StringPoolChunk) chunk;
} }
/** /** Returns all {@link TypeChunk} in this package. */
* Returns all {@link TypeChunk} in this package.
*/
public Collection<TypeChunk> getTypeChunks() { public Collection<TypeChunk> getTypeChunks() {
return types.values(); return types.values();
} }
@@ -194,16 +172,12 @@ public final class PackageChunk extends ChunkWithChunks {
return getTypeChunks(typeStringPool.indexOf(type) + 1); // Convert 0-based index to 1-based return getTypeChunks(typeStringPool.indexOf(type) + 1); // Convert 0-based index to 1-based
} }
/** /** Returns all {@link TypeSpecChunk} in this package. */
* Returns all {@link TypeSpecChunk} in this package.
*/
public Collection<TypeSpecChunk> getTypeSpecChunks() { public Collection<TypeSpecChunk> getTypeSpecChunks() {
return typeSpecs.values(); return typeSpecs.values();
} }
/** /** For a given (1-based) type id, returns the {@link TypeSpecChunk} matching it. */
* For a given (1-based) type id, returns the {@link TypeSpecChunk} matching it.
*/
public TypeSpecChunk getTypeSpecChunk(int id) { public TypeSpecChunk getTypeSpecChunk(int id) {
return Preconditions.checkNotNull(typeSpecs.get(id)); return Preconditions.checkNotNull(typeSpecs.get(id));
} }
@@ -217,16 +191,12 @@ public final class PackageChunk extends ChunkWithChunks {
return getTypeSpecChunk(typeStringPool.indexOf(type) + 1); // Convert 0-based index to 1-based return getTypeSpecChunk(typeStringPool.indexOf(type) + 1); // Convert 0-based index to 1-based
} }
/** /** Returns the name of this package. */
* Returns the name of this package.
*/
public String getPackageName() { public String getPackageName() {
return packageName; return packageName;
} }
/** /** Set the package name */
* Set the package name
*/
public void setPackageName(String packageName) { public void setPackageName(String packageName) {
this.packageName = packageName; this.packageName = packageName;
} }
@@ -20,20 +20,16 @@ import java.nio.ByteBuffer;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
/** /** Provides utility methods for package names. */
* Provides utility methods for package names.
*/
public final class PackageUtils { public final class PackageUtils {
public static final int PACKAGE_NAME_SIZE = 256; public static final int PACKAGE_NAME_SIZE = 256;
private PackageUtils() { private PackageUtils() {} // Prevent instantiation
} // Prevent instantiation
/** /**
* Reads the package name from the buffer and repositions the buffer to point directly after * Reads the package name from the buffer and repositions the buffer to point directly after
* the package name. * the package name.
*
* @param buffer The buffer containing the package name. * @param buffer The buffer containing the package name.
* @param offset The offset in the buffer to read from. * @param offset The offset in the buffer to read from.
* @return The package name. * @return The package name.
@@ -57,7 +53,6 @@ public final class PackageUtils {
/** /**
* Writes the provided package name to the buffer in UTF-16. * Writes the provided package name to the buffer in UTF-16.
*
* @param buffer The buffer that will be written to. * @param buffer The buffer that will be written to.
* @param packageName The package name that will be written to the buffer. * @param packageName The package name that will be written to the buffer.
*/ */
@@ -26,19 +26,15 @@ import java.util.Map.Entry;
/** /**
* Calculates extra information about an {@link ResourceEntry}, such as the total * Calculates extra information about an {@link ResourceEntry}, such as the total
* APK size the entry is responsible for. * APK size the entry is responsible for.
* <p> *
* This class is not thread-safe. * This class is not thread-safe.
*/ */
public class ResourceEntryStatsCollector { public class ResourceEntryStatsCollector {
/** /** The size in bytes of an offset in a chunk. */
* The size in bytes of an offset in a chunk.
*/
private static final int OFFSET_SIZE = 4; private static final int OFFSET_SIZE = 4;
/** /** The size in bytes of overhead for styles, if present, in {@link StringPoolChunk}. */
* The size in bytes of overhead for styles, if present, in {@link StringPoolChunk}.
*/
private static final int STYLE_OVERHEAD = 8; private static final int STYLE_OVERHEAD = 8;
/** /**
@@ -71,17 +67,13 @@ public class ResourceEntryStatsCollector {
computePackageSizes(); computePackageSizes();
} }
/** /** Returns entries for which there are computed stats. Must first call {@link #compute}. */
* Returns entries for which there are computed stats. Must first call {@link #compute}.
*/
public Map<ResourceEntry, ResourceStatistics> getStats() { public Map<ResourceEntry, ResourceStatistics> getStats() {
Preconditions.checkState(!stats.isEmpty(), "Must call #compute() first."); Preconditions.checkState(!stats.isEmpty(), "Must call #compute() first.");
return Collections.unmodifiableMap(stats); return Collections.unmodifiableMap(stats);
} }
/** /** Returns computed stats for a given entry. Must first call {@link #compute}. */
* Returns computed stats for a given entry. Must first call {@link #compute}.
*/
public ResourceStatistics getStats(ResourceEntry entry) { public ResourceStatistics getStats(ResourceEntry entry) {
Preconditions.checkState(!stats.isEmpty(), "Must call #compute() first."); Preconditions.checkState(!stats.isEmpty(), "Must call #compute() first.");
return stats.containsKey(entry) ? stats.get(entry) : ResourceStatistics.EMPTY; return stats.containsKey(entry) ? stats.get(entry) : ResourceStatistics.EMPTY;
@@ -193,9 +185,7 @@ public class ResourceEntryStatsCollector {
return computeStringSize(stringPool, index) + computeStyleSize(stringPool, index); return computeStringSize(stringPool, index) + computeStyleSize(stringPool, index);
} }
/** /** Given an {@code index} into a {@code stringPool}, return string's total size in bytes. */
* Given an {@code index} into a {@code stringPool}, return string's total size in bytes.
*/
private int computeStringSize(StringPoolChunk stringPool, int index) { private int computeStringSize(StringPoolChunk stringPool, int index) {
String string = stringPool.getString(index); String string = stringPool.getString(index);
int result = BinaryResourceString.encodeString(string, stringPool.getStringType()).length; int result = BinaryResourceString.encodeString(string, stringPool.getStringType()).length;
@@ -248,40 +238,29 @@ public class ResourceEntryStatsCollector {
} }
} }
/** /** Stats for an individual {@link ResourceEntry}. */
* Stats for an individual {@link ResourceEntry}.
*/
public static class ResourceStatistics { public static class ResourceStatistics {
/** /** The empty, immutable instance of ResourceStatistics which contains 0 for all values. */
* The empty, immutable instance of ResourceStatistics which contains 0 for all values.
*/
public static final ResourceStatistics EMPTY = new ResourceStatistics(); public static final ResourceStatistics EMPTY = new ResourceStatistics();
private int privateSize = 0; private int privateSize = 0;
private int sharedSize = 0; private int sharedSize = 0;
private double proportionalSize = 0; private double proportionalSize = 0;
private ResourceStatistics() { private ResourceStatistics() {}
}
/** /** The number of bytes that would be freed if this resource was removed. */
* The number of bytes that would be freed if this resource was removed.
*/
public int getPrivateSize() { public int getPrivateSize() {
return privateSize; return privateSize;
} }
/** /** The number of bytes taken up by this resource that are also shared with other resources. */
* The number of bytes taken up by this resource that are also shared with other resources.
*/
public int getSharedSize() { public int getSharedSize() {
return sharedSize; return sharedSize;
} }
/** /** The total size this resource is responsible for. */
* The total size this resource is responsible for.
*/
public double getProportionalSize() { public double getProportionalSize() {
return proportionalSize; return proportionalSize;
} }
@@ -16,9 +16,9 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import androidx.annotation.Nullable;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@@ -36,16 +36,13 @@ import java.util.Map;
*/ */
public final class ResourceTableChunk extends ChunkWithChunks { public final class ResourceTableChunk extends ChunkWithChunks {
/** /** A string pool containing all string resource values in the entire resource table. */
* The packages contained in this resource table.
*/
private final Map<String, PackageChunk> packages = new HashMap<>();
/**
* A string pool containing all string resource values in the entire resource table.
*/
private StringPoolChunk stringPool; private StringPoolChunk stringPool;
ResourceTableChunk(ByteBuffer buffer, @Nullable Chunk parent) { /** The packages contained in this resource table. */
private final Map<String, PackageChunk> packages = new HashMap<>();
protected ResourceTableChunk(ByteBuffer buffer, @Nullable Chunk parent) {
super(buffer, parent); super(buffer, parent);
// packageCount. We ignore this, because we already know how many chunks we have. // packageCount. We ignore this, because we already know how many chunks we have.
Preconditions.checkState(buffer.getInt() >= 1, "ResourceTableChunk package count was < 1."); Preconditions.checkState(buffer.getInt() >= 1, "ResourceTableChunk package count was < 1.");
@@ -66,24 +63,18 @@ public final class ResourceTableChunk extends ChunkWithChunks {
Preconditions.checkNotNull(stringPool, "ResourceTableChunk must have a string pool."); Preconditions.checkNotNull(stringPool, "ResourceTableChunk must have a string pool.");
} }
/** /** Returns the string pool containing all string resource values in the resource table. */
* Returns the string pool containing all string resource values in the resource table.
*/
public StringPoolChunk getStringPool() { public StringPoolChunk getStringPool() {
return stringPool; return stringPool;
} }
/** /** Returns the package with the given {@code packageName}. Else, returns null. */
* Returns the package with the given {@code packageName}. Else, returns null.
*/
@Nullable @Nullable
public PackageChunk getPackage(String packageName) { public PackageChunk getPackage(String packageName) {
return packages.get(packageName); return packages.get(packageName);
} }
/** /** Returns the packages contained in this resource table. */
* Returns the packages contained in this resource table.
*/
public Collection<PackageChunk> getPackages() { public Collection<PackageChunk> getPackages() {
return Collections.unmodifiableCollection(packages.values()); return Collections.unmodifiableCollection(packages.values());
} }
@@ -25,7 +25,6 @@ public interface SerializableResource {
/** /**
* Converts this resource into an array of bytes representation. * Converts this resource into an array of bytes representation.
*
* @return An array of bytes representing this resource. * @return An array of bytes representing this resource.
* @throws IOException * @throws IOException
*/ */
@@ -33,7 +32,6 @@ public interface SerializableResource {
/** /**
* Converts this resource into an array of bytes representation. * Converts this resource into an array of bytes representation.
*
* @param shrink True if, when converting to a byte array, this resource can modify the returned * @param shrink True if, when converting to a byte array, this resource can modify the returned
* bytes in an effort to reduce the size. * bytes in an effort to reduce the size.
* @return An array of bytes representing this resource. * @return An array of bytes representing this resource.
@@ -16,11 +16,11 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.ImmutableList.Builder;
import com.google.common.io.LittleEndianDataOutputStream; import com.google.common.io.LittleEndianDataOutputStream;
import androidx.annotation.Nullable;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
@@ -28,33 +28,23 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.*; import java.util.*;
/** /** Represents a string pool structure. */
* Represents a string pool structure.
*/
public final class StringPoolChunk extends Chunk { public final class StringPoolChunk extends Chunk {
// These are the defined flags for the "flags" field of ResourceStringPoolHeader // These are the defined flags for the "flags" field of ResourceStringPoolHeader
private static final int SORTED_FLAG = 1 << 0; private static final int SORTED_FLAG = 1 << 0;
private static final int UTF8_FLAG = 1 << 8; private static final int UTF8_FLAG = 1 << 8;
/** /** The offset from the start of the header that the stylesStart field is at. */
* The offset from the start of the header that the stylesStart field is at.
*/
private static final int STYLE_START_OFFSET = 24; private static final int STYLE_START_OFFSET = 24;
/** /** Flags. */
* Flags.
*/
private final int flags; private final int flags;
/** /** Index from header of the string data. */
* Index from header of the string data.
*/
private final int stringsStart; private final int stringsStart;
/** /** Index from header of the style data. */
* Index from header of the style data.
*/
private final int stylesStart; private final int stylesStart;
/** /**
@@ -89,7 +79,7 @@ public final class StringPoolChunk extends Chunk {
*/ */
private boolean isOriginalDeduped = false; private boolean isOriginalDeduped = false;
StringPoolChunk(ByteBuffer buffer, @Nullable Chunk parent) { protected StringPoolChunk(ByteBuffer buffer, @Nullable Chunk parent) {
super(buffer, parent); super(buffer, parent);
stringCount = buffer.getInt(); stringCount = buffer.getInt();
styleCount = buffer.getInt(); styleCount = buffer.getInt();
@@ -126,13 +116,11 @@ public final class StringPoolChunk extends Chunk {
return strings.get(index); return strings.get(index);
} }
public void updateString(int index, String value) { public void updateString(int index, String value){
strings.set(index, value); strings.set(index, value);
} }
/** /** Returns the number of strings in this pool. */
* Returns the number of strings in this pool.
*/
public int getStringCount() { public int getStringCount() {
return strings.size(); return strings.size();
} }
@@ -147,16 +135,12 @@ public final class StringPoolChunk extends Chunk {
return styles.get(index); return styles.get(index);
} }
/** /** Returns the number of styles in this pool. */
* Returns the number of styles in this pool.
*/
public int getStyleCount() { public int getStyleCount() {
return styles.size(); return styles.size();
} }
/** /** Returns the type of strings in this pool. */
* Returns the type of strings in this pool.
*/
public BinaryResourceString.Type getStringType() { public BinaryResourceString.Type getStringType() {
return isUTF8() ? BinaryResourceString.Type.UTF8 : BinaryResourceString.Type.UTF16; return isUTF8() ? BinaryResourceString.Type.UTF8 : BinaryResourceString.Type.UTF16;
} }
@@ -166,9 +150,7 @@ public final class StringPoolChunk extends Chunk {
return Type.STRING_POOL; return Type.STRING_POOL;
} }
/** /** Returns the number of bytes needed for offsets based on {@code strings} and {@code styles}. */
* Returns the number of bytes needed for offsets based on {@code strings} and {@code styles}.
*/
private int getOffsetSize() { private int getOffsetSize() {
return (strings.size() + styles.size()) * 4; return (strings.size() + styles.size()) * 4;
} }
@@ -310,10 +292,6 @@ public final class StringPoolChunk extends Chunk {
static final int RES_STRING_POOL_SPAN_END = 0xFFFFFFFF; static final int RES_STRING_POOL_SPAN_END = 0xFFFFFFFF;
private final List<StringPoolSpan> spans; private final List<StringPoolSpan> spans;
private StringPoolStyle(List<StringPoolSpan> spans) {
this.spans = spans;
}
static StringPoolStyle create(ByteBuffer buffer, int offset, StringPoolChunk parent) { static StringPoolStyle create(ByteBuffer buffer, int offset, StringPoolChunk parent) {
Builder<StringPoolSpan> spans = ImmutableList.builder(); Builder<StringPoolSpan> spans = ImmutableList.builder();
int nameIndex = buffer.getInt(offset); int nameIndex = buffer.getInt(offset);
@@ -325,6 +303,10 @@ public final class StringPoolChunk extends Chunk {
return new StringPoolStyle(spans.build()); return new StringPoolStyle(spans.build());
} }
private StringPoolStyle(List<StringPoolSpan> spans) {
this.spans = spans;
}
@Override @Override
public byte[] toByteArray() throws IOException { public byte[] toByteArray() throws IOException {
return toByteArray(false); return toByteArray(false);
@@ -352,7 +334,7 @@ public final class StringPoolChunk extends Chunk {
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
StringPoolStyle that = (StringPoolStyle) o; StringPoolStyle that = (StringPoolStyle)o;
return Objects.equals(spans, that.spans); return Objects.equals(spans, that.spans);
} }
@@ -373,9 +355,7 @@ public final class StringPoolChunk extends Chunk {
} }
} }
/** /** Represents a styled span associated with a specific string. */
* Represents a styled span associated with a specific string.
*/
private static class StringPoolSpan implements SerializableResource { private static class StringPoolSpan implements SerializableResource {
static final int SPAN_LENGTH = 12; static final int SPAN_LENGTH = 12;
@@ -384,13 +364,6 @@ public final class StringPoolChunk extends Chunk {
private final int stop; private final int stop;
private final StringPoolChunk parent; private final StringPoolChunk parent;
private StringPoolSpan(int nameIndex, int start, int stop, StringPoolChunk parent) {
this.nameIndex = nameIndex;
this.start = start;
this.stop = stop;
this.parent = parent;
}
static StringPoolSpan create(ByteBuffer buffer, int offset, StringPoolChunk parent) { static StringPoolSpan create(ByteBuffer buffer, int offset, StringPoolChunk parent) {
int nameIndex = buffer.getInt(offset); int nameIndex = buffer.getInt(offset);
int start = buffer.getInt(offset + 4); int start = buffer.getInt(offset + 4);
@@ -398,6 +371,13 @@ public final class StringPoolChunk extends Chunk {
return new StringPoolSpan(nameIndex, start, stop, parent); return new StringPoolSpan(nameIndex, start, stop, parent);
} }
private StringPoolSpan(int nameIndex, int start, int stop, StringPoolChunk parent) {
this.nameIndex = nameIndex;
this.start = start;
this.stop = stop;
this.parent = parent;
}
@Override @Override
public final byte[] toByteArray() { public final byte[] toByteArray() {
return toByteArray(false); return toByteArray(false);
@@ -416,7 +396,7 @@ public final class StringPoolChunk extends Chunk {
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
StringPoolSpan that = (StringPoolSpan) o; StringPoolSpan that = (StringPoolSpan)o;
return nameIndex == that.nameIndex && return nameIndex == that.nameIndex &&
start == that.start && start == that.start &&
stop == that.stop && stop == that.stop &&
@@ -16,11 +16,11 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.io.LittleEndianDataOutputStream; import com.google.common.io.LittleEndianDataOutputStream;
import com.google.common.primitives.UnsignedBytes; import com.google.common.primitives.UnsignedBytes;
import androidx.annotation.Nullable;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
@@ -38,30 +38,22 @@ import java.util.*;
*/ */
public final class TypeChunk extends Chunk { public final class TypeChunk extends Chunk {
/** /** The type identifier of the resource type this chunk is holding. */
* The type identifier of the resource type this chunk is holding.
*/
private final int id; private final int id;
/** /** The number of resources of this type at creation time. */
* The number of resources of this type at creation time.
*/
private final int entryCount; private final int entryCount;
/** /** The offset (from {@code offset}) in the original buffer where {@code entries} start. */
* The offset (from {@code offset}) in the original buffer where {@code entries} start.
*/
private final int entriesStart; private final int entriesStart;
/**
* A sparse list of resource entries defined by this chunk. /** The resource configuration that these resource entries correspond to. */
*/
private final Map<Integer, Entry> entries = new TreeMap<>();
/**
* The resource configuration that these resource entries correspond to.
*/
private BinaryResourceConfiguration configuration; private BinaryResourceConfiguration configuration;
TypeChunk(ByteBuffer buffer, @Nullable Chunk parent) { /** A sparse list of resource entries defined by this chunk. */
private final Map<Integer, Entry> entries = new TreeMap<>();
protected TypeChunk(ByteBuffer buffer, @Nullable Chunk parent) {
super(buffer, parent); super(buffer, parent);
id = UnsignedBytes.toInt(buffer.get()); id = UnsignedBytes.toInt(buffer.get());
buffer.position(buffer.position() + 3); // Skip 3 bytes for packing buffer.position(buffer.position() + 3); // Skip 3 bytes for packing
@@ -81,16 +73,12 @@ public final class TypeChunk extends Chunk {
} }
} }
/** /** Returns the (1-based) type id of the resource types that this {@link TypeChunk} is holding. */
* Returns the (1-based) type id of the resource types that this {@link TypeChunk} is holding.
*/
public int getId() { public int getId() {
return id; return id;
} }
/** /** Returns the name of the type this chunk represents (e.g. string, attr, id). */
* Returns the name of the type this chunk represents (e.g. string, attr, id).
*/
public String getTypeName() { public String getTypeName() {
PackageChunk packageChunk = getPackageChunk(); PackageChunk packageChunk = getPackageChunk();
Preconditions.checkNotNull(packageChunk, "%s has no parent package.", getClass()); Preconditions.checkNotNull(packageChunk, "%s has no parent package.", getClass());
@@ -99,9 +87,7 @@ public final class TypeChunk extends Chunk {
return typePool.getString(getId() - 1); // - 1 here to convert to 0-based index return typePool.getString(getId() - 1); // - 1 here to convert to 0-based index
} }
/** /** Returns the resource configuration that these resource entries correspond to. */
* Returns the resource configuration that these resource entries correspond to.
*/
public BinaryResourceConfiguration getConfiguration() { public BinaryResourceConfiguration getConfiguration() {
return configuration; return configuration;
} }
@@ -115,23 +101,17 @@ public final class TypeChunk extends Chunk {
this.configuration = configuration; this.configuration = configuration;
} }
/** /** Returns the total number of entries for this type + configuration, including null entries. */
* Returns the total number of entries for this type + configuration, including null entries.
*/
public int getTotalEntryCount() { public int getTotalEntryCount() {
return entryCount; return entryCount;
} }
/** /** Returns a sparse list of 0-based indices to resource entries defined by this chunk. */
* Returns a sparse list of 0-based indices to resource entries defined by this chunk.
*/
public Map<Integer, Entry> getEntries() { public Map<Integer, Entry> getEntries() {
return Collections.unmodifiableMap(entries); return Collections.unmodifiableMap(entries);
} }
/** /** Returns true if this chunk contains an entry for {@code resourceId}. */
* Returns true if this chunk contains an entry for {@code resourceId}.
*/
public boolean containsResource(BinaryResourceIdentifier resourceId) { public boolean containsResource(BinaryResourceIdentifier resourceId) {
PackageChunk packageChunk = Preconditions.checkNotNull(getPackageChunk()); PackageChunk packageChunk = Preconditions.checkNotNull(getPackageChunk());
int packageId = packageChunk.getId(); int packageId = packageChunk.getId();
@@ -174,13 +154,13 @@ public final class TypeChunk extends Chunk {
} }
} }
private String getString(int index) { protected String getString(int index) {
ResourceTableChunk resourceTable = getResourceTableChunk(); ResourceTableChunk resourceTable = getResourceTableChunk();
Preconditions.checkNotNull(resourceTable, "%s has no resource table.", getClass()); Preconditions.checkNotNull(resourceTable, "%s has no resource table.", getClass());
return resourceTable.getStringPool().getString(index); return resourceTable.getStringPool().getString(index);
} }
private String getKeyName(int index) { protected String getKeyName(int index) {
PackageChunk packageChunk = getPackageChunk(); PackageChunk packageChunk = getPackageChunk();
Preconditions.checkNotNull(packageChunk, "%s has no parent package.", getClass()); Preconditions.checkNotNull(packageChunk, "%s has no parent package.", getClass());
StringPoolChunk keyPool = packageChunk.getKeyStringPool(); StringPoolChunk keyPool = packageChunk.getKeyStringPool();
@@ -188,7 +168,7 @@ public final class TypeChunk extends Chunk {
return keyPool.getString(index); return keyPool.getString(index);
} }
private void updateKey(int index, String value) { protected void updateKey(int index, String value) {
PackageChunk packageChunk = getPackageChunk(); PackageChunk packageChunk = getPackageChunk();
Preconditions.checkNotNull(packageChunk, "%s has no parent package.", getClass()); Preconditions.checkNotNull(packageChunk, "%s has no parent package.", getClass());
StringPoolChunk keyPool = packageChunk.getKeyStringPool(); StringPoolChunk keyPool = packageChunk.getKeyStringPool();
@@ -205,9 +185,7 @@ public final class TypeChunk extends Chunk {
return chunk != null ? (ResourceTableChunk) chunk : null; return chunk != null ? (ResourceTableChunk) chunk : null;
} }
/** /** Returns the package enclosing this chunk, if any. Else, returns null. */
* Returns the package enclosing this chunk, if any. Else, returns null.
*/
@Nullable @Nullable
public PackageChunk getPackageChunk() { public PackageChunk getPackageChunk() {
Chunk chunk = getParent(); Chunk chunk = getParent();
@@ -222,9 +200,7 @@ public final class TypeChunk extends Chunk {
return Type.TABLE_TYPE; return Type.TABLE_TYPE;
} }
/** /** Returns the number of bytes needed for offsets based on {@code entries}. */
* Returns the number of bytes needed for offsets based on {@code entries}.
*/
private int getOffsetSize() { private int getOffsetSize() {
return entryCount * 4; return entryCount * 4;
} }
@@ -268,33 +244,25 @@ public final class TypeChunk extends Chunk {
output.write(baos.toByteArray()); output.write(baos.toByteArray());
} }
/** /** An {@link Entry} in a {@link TypeChunk}. Contains one or more {@link BinaryResourceValue}. */
* An {@link Entry} in a {@link TypeChunk}. Contains one or more {@link BinaryResourceValue}.
*/
public static class Entry implements SerializableResource { public static class Entry implements SerializableResource {
/** /** An entry offset that indicates that a given resource is not present. */
* An entry offset that indicates that a given resource is not present.
*/
public static final int NO_ENTRY = 0xFFFFFFFF; public static final int NO_ENTRY = 0xFFFFFFFF;
/** /** Set if this is a complex resource. Otherwise, it's a simple resource. */
* Set if this is a complex resource. Otherwise, it's a simple resource.
*/
private static final int FLAG_COMPLEX = 0x0001; private static final int FLAG_COMPLEX = 0x0001;
/** /** Size of a single resource id + value mapping entry. */
* Size of a single resource id + value mapping entry.
*/
private static final int MAPPING_SIZE = 4 + BinaryResourceValue.SIZE; private static final int MAPPING_SIZE = 4 + BinaryResourceValue.SIZE;
private final int headerSize; private final int headerSize;
private final int flags; private final int flags;
private final int keyIndex; private final int keyIndex;
private BinaryResourceValue value;
private Map<Integer, BinaryResourceValue> values;
private final int parentEntry; private final int parentEntry;
private final TypeChunk parent; private final TypeChunk parent;
private BinaryResourceValue value;
private final Map<Integer, BinaryResourceValue> values;
private Entry(int headerSize, private Entry(int headerSize,
int flags, int flags,
@@ -312,6 +280,75 @@ public final class TypeChunk extends Chunk {
this.parent = parent; this.parent = parent;
} }
/** Number of bytes in the header of the {@link Entry}. */
public int headerSize() { return headerSize; }
/** Resource entry flags. */
public int flags() { return flags; }
/** Index into {@link PackageChunk#getKeyStringPool} identifying this entry. */
public int keyIndex() { return keyIndex; }
/** The value of this resource entry, if this is not a complex entry. Else, null. */
@Nullable
public BinaryResourceValue value() { return value; }
/**
* Update the value of this resource entry
* @param value
*/
public void updateValue(@Nullable BinaryResourceValue value){
this.value = value;
}
/** The extra values in this resource entry if this {@link #isComplex}. */
public Map<Integer, BinaryResourceValue> values() { return values; }
/** Update the value in this resource entry if this {@link #isComplex}. */
public void updateValue(int index, BinaryResourceValue value){
if (index >= 0) {
if (value != null) {
values.put(index, value);
} else {
values.remove(index);
}
}
}
/**
* Entry into {@link PackageChunk} that is the parent {@link Entry} to this entry.
* This value only makes sense when this is complex ({@link #isComplex} returns true).
*/
public int parentEntry() { return parentEntry; }
/** The {@link TypeChunk} that this resource entry belongs to. */
public TypeChunk parent() { return parent; }
/** Returns the name of the type this chunk represents (e.g. string, attr, id). */
public final String typeName() {
return parent().getTypeName();
}
/** The total number of bytes that this {@link Entry} takes up. */
public final int size() {
return headerSize() + (isComplex() ? values().size() * MAPPING_SIZE : BinaryResourceValue.SIZE);
}
/** Returns the key name identifying this resource entry. */
public final String key() {
return parent().getKeyName(keyIndex());
}
/** Update the key name in this resource entry. */
public final void updateKey(int keyIndex, String value) {
parent().updateKey(keyIndex, value);
}
/** Returns true if this is a complex resource. */
public final boolean isComplex() {
return (flags() & FLAG_COMPLEX) != 0;
}
/** /**
* Creates a new {@link Entry} whose contents start at the 0-based position in * Creates a new {@link Entry} whose contents start at the 0-based position in
* {@code buffer} given by a 4-byte value read from {@code buffer} and then added to * {@code buffer} given by a 4-byte value read from {@code buffer} and then added to
@@ -358,114 +395,6 @@ public final class TypeChunk extends Chunk {
return new Entry(headerSize, flags, keyIndex, value, values, parentEntry, parent); return new Entry(headerSize, flags, keyIndex, value, values, parentEntry, parent);
} }
/**
* Number of bytes in the header of the {@link Entry}.
*/
public int headerSize() {
return headerSize;
}
/**
* Resource entry flags.
*/
public int flags() {
return flags;
}
/**
* Index into {@link PackageChunk#getKeyStringPool} identifying this entry.
*/
public int keyIndex() {
return keyIndex;
}
/**
* The value of this resource entry, if this is not a complex entry. Else, null.
*/
@Nullable
public BinaryResourceValue value() {
return value;
}
/**
* Update the value of this resource entry
*
* @param value
*/
public void updateValue(@Nullable BinaryResourceValue value) {
this.value = value;
}
/**
* The extra values in this resource entry if this {@link #isComplex}.
*/
public Map<Integer, BinaryResourceValue> values() {
return values;
}
/**
* Update the value in this resource entry if this {@link #isComplex}.
*/
public void updateValue(int index, BinaryResourceValue value) {
if (index >= 0) {
if (value != null) {
values.put(index, value);
} else {
values.remove(index);
}
}
}
/**
* Entry into {@link PackageChunk} that is the parent {@link Entry} to this entry.
* This value only makes sense when this is complex ({@link #isComplex} returns true).
*/
public int parentEntry() {
return parentEntry;
}
/**
* The {@link TypeChunk} that this resource entry belongs to.
*/
public TypeChunk parent() {
return parent;
}
/**
* Returns the name of the type this chunk represents (e.g. string, attr, id).
*/
public final String typeName() {
return parent().getTypeName();
}
/**
* The total number of bytes that this {@link Entry} takes up.
*/
public final int size() {
return headerSize() + (isComplex() ? values().size() * MAPPING_SIZE : BinaryResourceValue.SIZE);
}
/**
* Returns the key name identifying this resource entry.
*/
public final String key() {
return parent().getKeyName(keyIndex());
}
/**
* Update the key name in this resource entry.
*/
public final void updateKey(int keyIndex, String value) {
parent().updateKey(keyIndex, value);
}
/**
* Returns true if this is a complex resource.
*/
public final boolean isComplex() {
return (flags() & FLAG_COMPLEX) != 0;
}
@Override @Override
public final byte[] toByteArray() { public final byte[] toByteArray() {
return toByteArray(false); return toByteArray(false);
@@ -502,7 +431,7 @@ public final class TypeChunk extends Chunk {
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
Entry entry = (Entry) o; Entry entry = (Entry)o;
return headerSize == entry.headerSize && return headerSize == entry.headerSize &&
flags == entry.flags && flags == entry.flags &&
keyIndex == entry.keyIndex && keyIndex == entry.keyIndex &&
@@ -16,30 +16,24 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.primitives.UnsignedBytes; import com.google.common.primitives.UnsignedBytes;
import androidx.annotation.Nullable;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /** A chunk that contains a collection of resource entries for a particular resource data type. */
* A chunk that contains a collection of resource entries for a particular resource data type.
*/
public final class TypeSpecChunk extends Chunk { public final class TypeSpecChunk extends Chunk {
/** /** The id of the resource type that this type spec refers to. */
* The id of the resource type that this type spec refers to.
*/
private final int id; private final int id;
/** /** Resource configuration masks. */
* Resource configuration masks.
*/
private final int[] resources; private final int[] resources;
TypeSpecChunk(ByteBuffer buffer, @Nullable Chunk parent) { protected TypeSpecChunk(ByteBuffer buffer, @Nullable Chunk parent) {
super(buffer, parent); super(buffer, parent);
id = UnsignedBytes.toInt(buffer.get()); id = UnsignedBytes.toInt(buffer.get());
buffer.position(buffer.position() + 3); // Skip 3 bytes for packing buffer.position(buffer.position() + 3); // Skip 3 bytes for packing
@@ -59,9 +53,7 @@ public final class TypeSpecChunk extends Chunk {
return id; return id;
} }
/** /** Returns the number of resource entries that this chunk has configuration masks for. */
* Returns the number of resource entries that this chunk has configuration masks for.
*/
public int getResourceCount() { public int getResourceCount() {
return resources.length; return resources.length;
} }
@@ -71,9 +63,7 @@ public final class TypeSpecChunk extends Chunk {
return Type.TABLE_TYPE_SPEC; return Type.TABLE_TYPE_SPEC;
} }
/** /** Returns the name of the type this chunk represents (e.g. string, attr, id). */
* Returns the name of the type this chunk represents (e.g. string, attr, id).
*/
public String getTypeName() { public String getTypeName() {
PackageChunk packageChunk = getPackageChunk(); PackageChunk packageChunk = getPackageChunk();
Preconditions.checkNotNull(packageChunk, "%s has no parent package.", getClass()); Preconditions.checkNotNull(packageChunk, "%s has no parent package.", getClass());
@@ -82,9 +72,7 @@ public final class TypeSpecChunk extends Chunk {
return typePool.getString(getId() - 1); // - 1 here to convert to 0-based index return typePool.getString(getId() - 1); // - 1 here to convert to 0-based index
} }
/** /** Returns the package enclosing this chunk, if any. Else, returns null. */
* Returns the package enclosing this chunk, if any. Else, returns null.
*/
@Nullable @Nullable
private PackageChunk getPackageChunk() { private PackageChunk getPackageChunk() {
Chunk chunk = getParent(); Chunk chunk = getParent();
@@ -17,7 +17,6 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -34,7 +33,7 @@ public final class UnknownChunk extends Chunk {
private final byte[] payload; private final byte[] payload;
UnknownChunk(ByteBuffer buffer, @Nullable Chunk parent) { protected UnknownChunk(ByteBuffer buffer, @Nullable Chunk parent) {
super(buffer, parent); super(buffer, parent);
type = Type.fromCode(buffer.getShort(offset)); type = Type.fromCode(buffer.getShort(offset));
@@ -20,14 +20,10 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.Objects; import java.util.Objects;
/** /** Represents an XML attribute and value. */
* Represents an XML attribute and value.
*/
public class XmlAttribute implements SerializableResource { public class XmlAttribute implements SerializableResource {
/** /** The serialized size in bytes of an {@link XmlAttribute}. */
* The serialized size in bytes of an {@link XmlAttribute}.
*/
public static final int SIZE = 12 + BinaryResourceValue.SIZE; public static final int SIZE = 12 + BinaryResourceValue.SIZE;
private final int namespaceIndex; private final int namespaceIndex;
@@ -36,18 +32,6 @@ public class XmlAttribute implements SerializableResource {
private final BinaryResourceValue typedValue; private final BinaryResourceValue typedValue;
private final XmlNodeChunk parent; private final XmlNodeChunk parent;
private XmlAttribute(int namespaceIndex,
int nameIndex,
int rawValueIndex,
BinaryResourceValue typedValue,
XmlNodeChunk parent) {
this.namespaceIndex = namespaceIndex;
this.nameIndex = nameIndex;
this.rawValueIndex = rawValueIndex;
this.typedValue = typedValue;
this.parent = parent;
}
/** /**
* Creates a new {@link XmlAttribute} based on the bytes at the current {@code buffer} position. * Creates a new {@link XmlAttribute} based on the bytes at the current {@code buffer} position.
* *
@@ -62,58 +46,54 @@ public class XmlAttribute implements SerializableResource {
return new XmlAttribute(namespace, name, rawValue, typedValue, parent); return new XmlAttribute(namespace, name, rawValue, typedValue, parent);
} }
/** private XmlAttribute(int namespaceIndex,
* A string reference to the namespace URI, or -1 if not present. int nameIndex,
*/ int rawValueIndex,
BinaryResourceValue typedValue,
XmlNodeChunk parent) {
this.namespaceIndex = namespaceIndex;
this.nameIndex = nameIndex;
this.rawValueIndex = rawValueIndex;
this.typedValue = typedValue;
this.parent = parent;
}
/** A string reference to the namespace URI, or -1 if not present. */
public int namespaceIndex() { public int namespaceIndex() {
return namespaceIndex; return namespaceIndex;
} }
/** /** A string reference to the attribute name. */
* A string reference to the attribute name.
*/
public int nameIndex() { public int nameIndex() {
return nameIndex; return nameIndex;
} }
/** /** A string reference to a string containing the character value. */
* A string reference to a string containing the character value.
*/
public int rawValueIndex() { public int rawValueIndex() {
return rawValueIndex; return rawValueIndex;
} }
/** /** A {@link BinaryResourceValue} instance containing the parsed value. */
* A {@link BinaryResourceValue} instance containing the parsed value.
*/
public BinaryResourceValue typedValue() { public BinaryResourceValue typedValue() {
return typedValue; return typedValue;
} }
/** /** The parent of this XML attribute; used for dereferencing the namespace and name. */
* The parent of this XML attribute; used for dereferencing the namespace and name.
*/
public XmlNodeChunk parent() { public XmlNodeChunk parent() {
return parent; return parent;
} }
/** /** The namespace URI, or the empty string if not present. */
* The namespace URI, or the empty string if not present.
*/
public final String namespace() { public final String namespace() {
return getString(namespaceIndex()); return getString(namespaceIndex());
} }
/** /** The attribute name, or the empty string if not present. */
* The attribute name, or the empty string if not present.
*/
public final String name() { public final String name() {
return getString(nameIndex()); return getString(nameIndex());
} }
/** /** The raw character value. */
* The raw character value.
*/
public final String rawValue() { public final String rawValue() {
return getString(rawValueIndex()); return getString(rawValueIndex());
} }
@@ -141,7 +121,7 @@ public class XmlAttribute implements SerializableResource {
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
XmlAttribute that = (XmlAttribute) o; XmlAttribute that = (XmlAttribute)o;
return namespaceIndex == that.namespaceIndex && return namespaceIndex == that.namespaceIndex &&
nameIndex == that.nameIndex && nameIndex == that.nameIndex &&
rawValueIndex == that.rawValueIndex && rawValueIndex == that.rawValueIndex &&
@@ -17,42 +17,31 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /** Represents an XML cdata node. */
* Represents an XML cdata node.
*/
public final class XmlCdataChunk extends XmlNodeChunk { public final class XmlCdataChunk extends XmlNodeChunk {
/** /** A string reference to a string containing the raw character data. */
* A string reference to a string containing the raw character data.
*/
private final int rawValue; private final int rawValue;
/** /** A {@link BinaryResourceValue} instance containing the parsed value. */
* A {@link BinaryResourceValue} instance containing the parsed value.
*/
private final BinaryResourceValue binaryResourceValue; private final BinaryResourceValue binaryResourceValue;
XmlCdataChunk(ByteBuffer buffer, @Nullable Chunk parent) { protected XmlCdataChunk(ByteBuffer buffer, @Nullable Chunk parent) {
super(buffer, parent); super(buffer, parent);
rawValue = buffer.getInt(); rawValue = buffer.getInt();
binaryResourceValue = BinaryResourceValue.create(buffer); binaryResourceValue = BinaryResourceValue.create(buffer);
} }
/** /** Returns a string containing the raw character data of this chunk. */
* Returns a string containing the raw character data of this chunk.
*/
public String getRawValue() { public String getRawValue() {
return getString(rawValue); return getString(rawValue);
} }
/** /** Returns a {@link BinaryResourceValue} instance containing the parsed cdata value. */
* Returns a {@link BinaryResourceValue} instance containing the parsed cdata value.
*/
public BinaryResourceValue getResourceValue() { public BinaryResourceValue getResourceValue() {
return binaryResourceValue; return binaryResourceValue;
} }
@@ -17,7 +17,6 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /**
@@ -28,7 +27,7 @@ import java.nio.ByteBuffer;
*/ */
public final class XmlChunk extends ChunkWithChunks { public final class XmlChunk extends ChunkWithChunks {
XmlChunk(ByteBuffer buffer, @Nullable Chunk parent) { protected XmlChunk(ByteBuffer buffer, @Nullable Chunk parent) {
super(buffer, parent); super(buffer, parent);
} }
@@ -37,9 +36,7 @@ public final class XmlChunk extends ChunkWithChunks {
return Type.XML; return Type.XML;
} }
/** /** Returns a string at the provided (0-based) index if the index exists in the string pool. */
* Returns a string at the provided (0-based) index if the index exists in the string pool.
*/
public String getString(int index) { public String getString(int index) {
for (Chunk chunk : getChunks().values()) { for (Chunk chunk : getChunks().values()) {
if (chunk instanceof StringPoolChunk) { if (chunk instanceof StringPoolChunk) {
@@ -17,42 +17,31 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /** Represents the end of an XML node. */
* Represents the end of an XML node.
*/
public final class XmlEndElementChunk extends XmlNodeChunk { public final class XmlEndElementChunk extends XmlNodeChunk {
/** /** A string reference to the namespace URI, or -1 if not present. */
* A string reference to the namespace URI, or -1 if not present.
*/
private final int namespace; private final int namespace;
/** /** A string reference to the attribute name. */
* A string reference to the attribute name.
*/
private final int name; private final int name;
XmlEndElementChunk(ByteBuffer buffer, @Nullable Chunk parent) { protected XmlEndElementChunk(ByteBuffer buffer, @Nullable Chunk parent) {
super(buffer, parent); super(buffer, parent);
namespace = buffer.getInt(); namespace = buffer.getInt();
name = buffer.getInt(); name = buffer.getInt();
} }
/** /** Returns the namespace URI, or the empty string if no namespace is present. */
* Returns the namespace URI, or the empty string if no namespace is present.
*/
public String getNamespace() { public String getNamespace() {
return getString(namespace); return getString(namespace);
} }
/** /** Returns the attribute name. */
* Returns the attribute name.
*/
public String getName() { public String getName() {
return getString(name); return getString(name);
} }
@@ -17,24 +17,17 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /** Represents the start/end of a namespace in an XML document. */
* Represents the start/end of a namespace in an XML document.
*/
public abstract class XmlNamespaceChunk extends XmlNodeChunk { public abstract class XmlNamespaceChunk extends XmlNodeChunk {
/** /** A string reference to the namespace prefix. */
* A string reference to the namespace prefix.
*/
private final int prefix; private final int prefix;
/** /** A string reference to the namespace URI. */
* A string reference to the namespace URI.
*/
private final int uri; private final int uri;
protected XmlNamespaceChunk(ByteBuffer buffer, @Nullable Chunk parent) { protected XmlNamespaceChunk(ByteBuffer buffer, @Nullable Chunk parent) {
@@ -43,16 +36,12 @@ public abstract class XmlNamespaceChunk extends XmlNodeChunk {
uri = buffer.getInt(); uri = buffer.getInt();
} }
/** /** Returns the namespace prefix. */
* Returns the namespace prefix.
*/
public String getPrefix() { public String getPrefix() {
return getString(prefix); return getString(prefix);
} }
/** /** Returns the namespace URI. */
* Returns the namespace URI.
*/
public String getUri() { public String getUri() {
return getString(uri); return getString(uri);
} }
@@ -17,15 +17,12 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /** Represents the ending tag of a namespace in an XML document. */
* Represents the ending tag of a namespace in an XML document.
*/
public final class XmlNamespaceEndChunk extends XmlNamespaceChunk { public final class XmlNamespaceEndChunk extends XmlNamespaceChunk {
XmlNamespaceEndChunk(ByteBuffer buffer, @Nullable Chunk parent) { protected XmlNamespaceEndChunk(ByteBuffer buffer, @Nullable Chunk parent) {
super(buffer, parent); super(buffer, parent);
} }
@@ -17,15 +17,12 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /** Represents the starting tag of a namespace in an XML document. */
* Represents the starting tag of a namespace in an XML document.
*/
public final class XmlNamespaceStartChunk extends XmlNamespaceChunk { public final class XmlNamespaceStartChunk extends XmlNamespaceChunk {
XmlNamespaceStartChunk(ByteBuffer buffer, @Nullable Chunk parent) { protected XmlNamespaceStartChunk(ByteBuffer buffer, @Nullable Chunk parent) {
super(buffer, parent); super(buffer, parent);
} }
@@ -17,22 +17,15 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /** The common superclass for the various types of XML nodes. */
* The common superclass for the various types of XML nodes.
*/
public abstract class XmlNodeChunk extends Chunk { public abstract class XmlNodeChunk extends Chunk {
/** /** The line number in the original source at which this node appeared. */
* The line number in the original source at which this node appeared.
*/
private final int lineNumber; private final int lineNumber;
/** /** A string reference of this node's comment. If this is -1, then there is no comment. */
* A string reference of this node's comment. If this is -1, then there is no comment.
*/
private final int comment; private final int comment;
protected XmlNodeChunk(ByteBuffer buffer, @Nullable Chunk parent) { protected XmlNodeChunk(ByteBuffer buffer, @Nullable Chunk parent) {
@@ -41,23 +34,17 @@ public abstract class XmlNodeChunk extends Chunk {
comment = buffer.getInt(); comment = buffer.getInt();
} }
/** /** Returns true if this XML node contains a comment. Else, returns false. */
* Returns true if this XML node contains a comment. Else, returns false.
*/
public boolean hasComment() { public boolean hasComment() {
return comment != -1; return comment != -1;
} }
/** /** Returns the line number in the original source at which this node appeared. */
* Returns the line number in the original source at which this node appeared.
*/
public int getLineNumber() { public int getLineNumber() {
return lineNumber; return lineNumber;
} }
/** /** Returns the comment associated with this node, if any. Else, returns the empty string. */
* Returns the comment associated with this node, if any. Else, returns the empty string.
*/
public String getComment() { public String getComment() {
return getString(comment); return getString(comment);
} }
@@ -17,7 +17,6 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -32,9 +31,7 @@ import java.util.List;
*/ */
public class XmlResourceMapChunk extends Chunk { public class XmlResourceMapChunk extends Chunk {
/** /** The size of a resource reference for {@code resources} in bytes. */
* The size of a resource reference for {@code resources} in bytes.
*/
private static final int RESOURCE_SIZE = 4; private static final int RESOURCE_SIZE = 4;
/** /**
@@ -68,9 +65,7 @@ public class XmlResourceMapChunk extends Chunk {
return result; return result;
} }
/** /** Returns the resource ID that this {@code attributeId} maps to. */
* Returns the resource ID that this {@code attributeId} maps to.
*/
public BinaryResourceIdentifier getResourceId(int attributeId) { public BinaryResourceIdentifier getResourceId(int attributeId) {
return BinaryResourceIdentifier.create(resources.get(attributeId)); return BinaryResourceIdentifier.create(resources.get(attributeId));
} }
@@ -16,9 +16,9 @@
package com.google.devrel.gmscore.tools.apk.arsc; package com.google.devrel.gmscore.tools.apk.arsc;
import androidx.annotation.Nullable;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import androidx.annotation.Nullable;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -26,52 +26,34 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
/** /** Represents the beginning of an XML node. */
* Represents the beginning of an XML node.
*/
public final class XmlStartElementChunk extends XmlNodeChunk { public final class XmlStartElementChunk extends XmlNodeChunk {
/** /** A string reference to the namespace URI, or -1 if not present. */
* A string reference to the namespace URI, or -1 if not present.
*/
private final int namespace; private final int namespace;
/** /** A string reference to the element name that this chunk represents. */
* A string reference to the element name that this chunk represents.
*/
private final int name; private final int name;
/** /** The offset to the start of the attributes payload. */
* The offset to the start of the attributes payload.
*/
private final int attributeStart; private final int attributeStart;
/** /** The number of attributes in the original buffer. */
* The number of attributes in the original buffer.
*/
private final int attributeCount; private final int attributeCount;
/** /** The (0-based) index of the id attribute, or -1 if not present. */
* The (0-based) index of the id attribute, or -1 if not present.
*/
private final int idIndex; private final int idIndex;
/** /** The (0-based) index of the class attribute, or -1 if not present. */
* The (0-based) index of the class attribute, or -1 if not present.
*/
private final int classIndex; private final int classIndex;
/** /** The (0-based) index of the style attribute, or -1 if not present. */
* The (0-based) index of the style attribute, or -1 if not present.
*/
private final int styleIndex; private final int styleIndex;
/** /** The XML attributes associated with this element. */
* The XML attributes associated with this element.
*/
private final List<XmlAttribute> attributes = new ArrayList<>(); private final List<XmlAttribute> attributes = new ArrayList<>();
XmlStartElementChunk(ByteBuffer buffer, @Nullable Chunk parent) { protected XmlStartElementChunk(ByteBuffer buffer, @Nullable Chunk parent) {
super(buffer, parent); super(buffer, parent);
namespace = buffer.getInt(); namespace = buffer.getInt();
name = buffer.getInt(); name = buffer.getInt();
@@ -109,23 +91,17 @@ public final class XmlStartElementChunk extends XmlNodeChunk {
return result; return result;
} }
/** /** Returns the namespace URI, or the empty string if not present. */
* Returns the namespace URI, or the empty string if not present.
*/
public String getNamespace() { public String getNamespace() {
return getString(namespace); return getString(namespace);
} }
/** /** Returns the element name that this chunk represents. */
* Returns the element name that this chunk represents.
*/
public String getName() { public String getName() {
return getString(name); return getString(name);
} }
/** /** Returns an unmodifiable list of this XML element's attributes. */
* Returns an unmodifiable list of this XML element's attributes.
*/
public List<XmlAttribute> getAttributes() { public List<XmlAttribute> getAttributes() {
return Collections.unmodifiableList(attributes); return Collections.unmodifiableList(attributes);
} }
@@ -6,9 +6,8 @@ import com.vk.api.base.ApiRequest;
import com.vk.dto.music.MusicTrack; import com.vk.dto.music.MusicTrack;
import com.vk.log.L; import com.vk.log.L;
import org.json.JSONObject; import org.json.JSONObject;
import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.lite.music.Genius; import ru.vtosters.lite.music.Genius;
import ru.vtosters.lite.utils.AndroidUtils; import ru.vtosters.lite.utils.Preferences;
import java.util.ArrayList; import java.util.ArrayList;
@@ -25,7 +24,7 @@ public class AudioGetLyrics extends ApiRequest<AudioGetLyrics.a> {
public a a(@NonNull JSONObject jSONObject) { public a a(@NonNull JSONObject jSONObject) {
var aVar = new a(); var aVar = new a();
if (Preferences.getBoolValue("useGenius", false) && !Preferences.serverFeaturesDisable()) { if (Preferences.getBoolValue("useGenius", false)) {
aVar.a = Genius.getTextMusic(musicTrack); aVar.a = Genius.getTextMusic(musicTrack);
return aVar; return aVar;
} }
@@ -66,7 +65,7 @@ public class AudioGetLyrics extends ApiRequest<AudioGetLyrics.a> {
return aVar; return aVar;
} catch (Exception e) { } catch (Exception e) {
L.e("vk", e); L.e("vk", e);
aVar.a = AndroidUtils.getString("failed_to_get_text") + "\n\n" + AndroidUtils.getString("error") + ": \n" + e.getLocalizedMessage(); aVar.a = "Ошибка получения текста" + "\n\n" + "Ошибка: \n" + e.getLocalizedMessage();
return aVar; return aVar;
} }
} }
@@ -1,12 +1,24 @@
package com.vk.api.gifts; package com.vk.api.gifts;
import android.content.Context; import android.content.Context;
import com.vk.api.base.ApiRequest; import com.vk.api.base.ApiRequest;
import com.vk.dto.gift.CatalogedGift; import com.vk.dto.gift.CatalogedGift;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
public class GiftGetByStickerId extends ApiRequest<GiftGetByStickerId.a> { public class GiftGetByStickerId extends ApiRequest<GiftGetByStickerId.a> {
public static class a {
public final int a;
public final CatalogedGift b;
public a(int i, CatalogedGift catalogedGift) {
this.a = i;
this.b = catalogedGift;
}
}
public GiftGetByStickerId(Context context, int i) { public GiftGetByStickerId(Context context, int i) {
super("execute.getGiftByStickerId"); super("execute.getGiftByStickerId");
b("sticker_id", i); b("sticker_id", i);
@@ -20,14 +32,4 @@ public class GiftGetByStickerId extends ApiRequest<GiftGetByStickerId.a> {
return new a(jSONObject2.optInt("balance"), return new a(jSONObject2.optInt("balance"),
new CatalogedGift(jSONObject2.getJSONObject("gift"))); new CatalogedGift(jSONObject2.getJSONObject("gift")));
} }
public static class a {
public final int a;
public final CatalogedGift b;
public a(int i, CatalogedGift catalogedGift) {
this.a = i;
this.b = catalogedGift;
}
}
} }
@@ -27,15 +27,6 @@ public class RecoloredDrawable extends Drawable implements Drawable.Callback {
onStateChange(new int[0]); onStateChange(new int[0]);
} }
public RecoloredDrawable(Drawable drawable, int i) {
this(drawable, new ColorStateList(new int[][]{new int[0]}, new int[]{i}));
}
public RecoloredDrawable() {
this.c = 255;
this.d = 255;
}
public void a(int i) { public void a(int i) {
a(new ColorStateList(new int[][]{new int[0]}, new int[]{i})); a(new ColorStateList(new int[][]{new int[0]}, new int[]{i}));
} }
@@ -129,4 +120,13 @@ public class RecoloredDrawable extends Drawable implements Drawable.Callback {
public Drawable a() { public Drawable a() {
return this.drawable; return this.drawable;
} }
public RecoloredDrawable(Drawable drawable, int i) {
this(drawable, new ColorStateList(new int[][]{new int[0]}, new int[]{i}));
}
public RecoloredDrawable() {
this.c = 255;
this.d = 255;
}
} }
@@ -1,128 +0,0 @@
package com.vk.core.extensions;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.AttrRes;
import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import b.h.v.InitialValueObservable;
import b.h.v.TextViewTextChangeEvent;
import b.h.v.TextViewTextChangeEventObservable;
import com.vk.core.util.ContextExtKt;
import ru.vtosters.hooks.other.ThemesUtils;
public final class TextViewExt {
public static void a(TextView textView, Drawable drawable) {
a(textView, null, drawable);
}
public static boolean b(TextView textView) {
return textView == null || TextUtils.isEmpty(textView.getEditableText());
}
public static InitialValueObservable<TextViewTextChangeEvent> c(TextView textView) {
return new TextViewTextChangeEventObservable(textView);
}
public static void d(TextView textView, @DrawableRes int i, @AttrRes int i2) {
b(textView, ThemesUtils.recolorDrawable(ContextExtKt.a(textView.getContext(), i, ContextExtKt.h(textView.getContext(), i2))));
}
public static void a(TextView textView, Drawable drawable, ColorStateList colorStateList) {
a(textView, null, a(drawable, colorStateList));
}
public static void b(TextView textView, Drawable drawable) {
a(textView, drawable, (Drawable) null);
}
public static void c(TextView textView, @DrawableRes int i, @ColorRes int i2) {
if (i == 0) {
b(textView, null);
} else if (i2 == 0) {
b(textView, ContextCompat.getDrawable(textView.getContext(), i));
} else {
b(textView, ContextCompat.getDrawable(textView.getContext(), i), ContextCompat.getColorStateList(textView.getContext(), i2));
}
}
public static void d(TextView textView, int i) {
textView.setTextSize(0, i);
}
public static void a(TextView textView, @DrawableRes int i) {
a(textView, i, 0);
}
public static void b(TextView textView, Drawable drawable, ColorStateList colorStateList) {
a(textView, a(drawable, colorStateList), (Drawable) null);
}
public static void a(TextView textView, @DrawableRes int i, @ColorRes int i2) {
if (i == 0) {
a(textView, (Drawable) null);
} else if (i2 == 0) {
a(textView, ContextCompat.getDrawable(textView.getContext(), i));
} else {
a(textView, ContextCompat.getDrawable(textView.getContext(), i), ContextCompat.getColorStateList(textView.getContext(), i2));
}
}
public static void b(TextView textView, @DrawableRes int i) {
c(textView, i, 0);
}
public static void b(TextView textView, @DrawableRes int i, @AttrRes int i2) {
if (i == 0) {
a(textView, (Drawable) null);
} else if (i2 == 0) {
a(textView, ContextCompat.getDrawable(textView.getContext(), i));
} else {
Drawable drawable = ContextCompat.getDrawable(textView.getContext(), i);
a(textView, drawable, ColorStateList.valueOf(ContextExtKt.h(textView.getContext(), i2)));
}
}
public static void c(TextView textView, @ColorRes int i) {
textView.setTextColor(ContextExtKt.a(textView.getContext(), i));
}
private static void a(TextView textView, Drawable drawable, Drawable drawable2) {
textView.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, drawable2, null);
}
public static void a(TextView textView) {
textView.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, null, null);
}
public static Drawable a(Drawable drawable, ColorStateList colorStateList) {
if (colorStateList == null) return drawable;
if (drawable != null) {
Drawable wrap = DrawableCompat.wrap(drawable.mutate());
DrawableCompat.setTintList(wrap, colorStateList);
return wrap;
}
return null;
}
public static void a(TextView textView, CharSequence charSequence) {
if (TextUtils.isEmpty(charSequence)) {
textView.setVisibility(View.GONE);
return;
}
textView.setVisibility(View.VISIBLE);
textView.setText(charSequence);
}
public static void a(TextView textView, float f) {
textView.setTextSize(0, f);
}
}
@@ -11,15 +11,13 @@ import android.net.Uri;
import android.os.Environment; import android.os.Environment;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import b.h.g.m.CameraUtils;
import b.h.g.m.FileUtils;
import com.facebook.common.i.MediaUtils; import com.facebook.common.i.MediaUtils;
import com.facebook.x.g.EncodedImage; import com.facebook.x.g.EncodedImage;
import com.vk.imageloader.VKImageLoader; import com.vk.imageloader.VKImageLoader;
import com.vk.log.L; import com.vk.log.L;
import com.vk.metrics.eventtracking.VkTracker; import com.vk.metrics.eventtracking.VkTracker;
import com.vtosters.lite.R; import com.vtosters.lite.R;
import ru.vtosters.lite.concurrent.VTExecutors;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@@ -28,6 +26,10 @@ import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.util.HashSet; import java.util.HashSet;
import b.h.g.m.CameraUtils;
import b.h.g.m.FileUtils;
import ru.vtosters.lite.concurrent.VTExecutors;
public class DownloadUtils { public class DownloadUtils {
public static final HashSet<Long> a = new HashSet<>(); public static final HashSet<Long> a = new HashSet<>();
@@ -14,20 +14,13 @@ import com.vk.core.ui.themes.VKThemeHelper;
import com.vk.dto.common.VerifyInfo; import com.vk.dto.common.VerifyInfo;
import com.vk.extensions.ViewExtKt; import com.vk.extensions.ViewExtKt;
import com.vtosters.lite.R; import com.vtosters.lite.R;
import ru.vtosters.hooks.other.ThemesUtils; import ru.vtosters.lite.utils.ThemesUtils;
public final class VerifyInfoHelper { public final class VerifyInfoHelper {
public static final VerifyInfoHelper h; public static final VerifyInfoHelper h;
public static int devIcon = R.drawable.ic_favorite_16; public static int devIcon = R.drawable.ic_favorite_16;
static {
h = new VerifyInfoHelper();
}
private VerifyInfoHelper() {
}
public static Integer enumSwitchMapping(VerifyInfoHelper.ColorTheme color) { public static Integer enumSwitchMapping(VerifyInfoHelper.ColorTheme color) {
return switch (color) { return switch (color) {
case normal -> 1; case normal -> 1;
@@ -37,47 +30,18 @@ public final class VerifyInfoHelper {
}; };
} }
public static Drawable b(VerifyInfoHelper verifyInfoHelper, boolean z, boolean z2, boolean dev, Context context, ColorTheme colorTheme, int i, Object obj) { public enum ColorTheme {
if ((i & 8) != 0) { white,
colorTheme = ColorTheme.normal; normal,
} light,
return verifyInfoHelper.b(z, z2, dev, context, colorTheme); ultraLight
} }
public static Drawable b(VerifyInfoHelper verifyInfoHelper, VerifyInfo verifyInfo, Context context, ColorTheme colorTheme, int i, Object obj) { static {
return b(verifyInfoHelper, verifyInfo.u1(), verifyInfo.t1(), verifyInfo.dev(), context, colorTheme, i, obj); h = new VerifyInfoHelper();
} }
public static Drawable b(VerifyInfoHelper verifyInfoHelper, boolean z, boolean z2, Context context, ColorTheme colorTheme, int i, Object obj) { private VerifyInfoHelper() {
return b(verifyInfoHelper, z, z2, false, context, colorTheme, i, obj);
}
public static Drawable a(VerifyInfoHelper verifyInfoHelper, VerifyInfo verifyInfo, Context context, ColorTheme colorTheme, int i, Object obj) {
if ((i & 4) != 0) {
colorTheme = ColorTheme.normal;
}
return verifyInfoHelper.b(verifyInfo, context, colorTheme);
}
public static Drawable a(VerifyInfoHelper verifyInfoHelper, boolean z, boolean z2, boolean dev, Context context, ColorTheme colorTheme, int i, Object obj) {
if ((i & 8) != 0) {
colorTheme = ColorTheme.normal;
}
return verifyInfoHelper.a(z, z2, dev, context, colorTheme);
}
public static Drawable a(VerifyInfoHelper verifyInfoHelper, boolean z, boolean z2, Context context, ColorTheme colorTheme, int i, Object obj) {
return a(verifyInfoHelper, z, z2, false, context, colorTheme, i, obj);
}
public static void a(VerifyInfoHelper verifyInfoHelper, TextView textView, VerifyInfo verifyInfo, boolean z, ColorTheme colorTheme, int i, Object obj) {
if ((i & 4) != 0) {
z = false;
}
if ((i & 8) != 0) {
colorTheme = ColorTheme.normal;
}
verifyInfoHelper.a(textView, verifyInfo, z, colorTheme);
} }
private int a() { private int a() {
@@ -125,6 +89,7 @@ public final class VerifyInfoHelper {
return b(this, z, z2, false, context, null, 8, null); return b(this, z, z2, false, context, null, 8, null);
} }
public int b(ColorTheme colorTheme) { public int b(ColorTheme colorTheme) {
return a(colorTheme); return a(colorTheme);
} }
@@ -139,6 +104,7 @@ public final class VerifyInfoHelper {
}; };
} }
public Drawable b(Context context, VerifyInfo verifyInfo) { public Drawable b(Context context, VerifyInfo verifyInfo) {
if (verifyInfo.dev()) { if (verifyInfo.dev()) {
return new RecoloredDrawable(ContextCompat.getDrawable(context, devIcon), c(ColorTheme.normal)); return new RecoloredDrawable(ContextCompat.getDrawable(context, devIcon), c(ColorTheme.normal));
@@ -157,6 +123,21 @@ public final class VerifyInfoHelper {
return b(verifyInfo.u1(), verifyInfo.t1(), verifyInfo.dev(), context, colorTheme); return b(verifyInfo.u1(), verifyInfo.t1(), verifyInfo.dev(), context, colorTheme);
} }
public static Drawable b(VerifyInfoHelper verifyInfoHelper, boolean z, boolean z2, boolean dev, Context context, ColorTheme colorTheme, int i, Object obj) {
if ((i & 8) != 0) {
colorTheme = ColorTheme.normal;
}
return verifyInfoHelper.b(z, z2, dev, context, colorTheme);
}
public static Drawable b(VerifyInfoHelper verifyInfoHelper, VerifyInfo verifyInfo, Context context, ColorTheme colorTheme, int i, Object obj) {
return b(verifyInfoHelper, verifyInfo.u1(), verifyInfo.t1(), verifyInfo.dev(), context, colorTheme, i, obj);
}
public static Drawable b(VerifyInfoHelper verifyInfoHelper, boolean z, boolean z2, Context context, ColorTheme colorTheme, int i, Object obj) {
return b(verifyInfoHelper, z, z2, false, context, colorTheme, i, obj);
}
public Drawable a(Context context, VerifyInfo verifyInfo) { public Drawable a(Context context, VerifyInfo verifyInfo) {
if (verifyInfo.dev()) { if (verifyInfo.dev()) {
return new RecoloredDrawable(ContextCompat.getDrawable(context, devIcon), c(ColorTheme.normal)); return new RecoloredDrawable(ContextCompat.getDrawable(context, devIcon), c(ColorTheme.normal));
@@ -200,10 +181,28 @@ public final class VerifyInfoHelper {
return new RecoloredDrawable(ContextCompat.getDrawable(context, i), c2); return new RecoloredDrawable(ContextCompat.getDrawable(context, i), c2);
} }
public static Drawable a(VerifyInfoHelper verifyInfoHelper, VerifyInfo verifyInfo, Context context, ColorTheme colorTheme, int i, Object obj) {
if ((i & 4) != 0) {
colorTheme = ColorTheme.normal;
}
return verifyInfoHelper.b(verifyInfo, context, colorTheme);
}
public Drawable a(VerifyInfo verifyInfo, Context context, ColorTheme colorTheme) { public Drawable a(VerifyInfo verifyInfo, Context context, ColorTheme colorTheme) {
return a(verifyInfo.u1(), verifyInfo.t1(), verifyInfo.dev(), context, colorTheme); return a(verifyInfo.u1(), verifyInfo.t1(), verifyInfo.dev(), context, colorTheme);
} }
public static Drawable a(VerifyInfoHelper verifyInfoHelper, boolean z, boolean z2, boolean dev, Context context, ColorTheme colorTheme, int i, Object obj) {
if ((i & 8) != 0) {
colorTheme = ColorTheme.normal;
}
return verifyInfoHelper.a(z, z2, dev, context, colorTheme);
}
public static Drawable a(VerifyInfoHelper verifyInfoHelper, boolean z, boolean z2, Context context, ColorTheme colorTheme, int i, Object obj) {
return a(verifyInfoHelper, z, z2, false, context, colorTheme, i, obj);
}
public Drawable a(boolean z, boolean z2, Context context, ColorTheme colorTheme) { public Drawable a(boolean z, boolean z2, Context context, ColorTheme colorTheme) {
return a(z, z2, false, context, colorTheme); return a(z, z2, false, context, colorTheme);
} }
@@ -231,6 +230,16 @@ public final class VerifyInfoHelper {
return new RecoloredDrawable(ContextCompat.getDrawable(context, i), c2); return new RecoloredDrawable(ContextCompat.getDrawable(context, i), c2);
} }
public static void a(VerifyInfoHelper verifyInfoHelper, TextView textView, VerifyInfo verifyInfo, boolean z, ColorTheme colorTheme, int i, Object obj) {
if ((i & 4) != 0) {
z = false;
}
if ((i & 8) != 0) {
colorTheme = ColorTheme.normal;
}
verifyInfoHelper.a(textView, verifyInfo, z, colorTheme);
}
public void a(TextView textView, VerifyInfo verifyInfo, boolean z, ColorTheme colorTheme) { public void a(TextView textView, VerifyInfo verifyInfo, boolean z, ColorTheme colorTheme) {
Drawable drawable; Drawable drawable;
Context context = textView.getContext(); Context context = textView.getContext();
@@ -258,11 +267,4 @@ public final class VerifyInfoHelper {
} }
ViewExtKt.p(imageView); ViewExtKt.p(imageView);
} }
public enum ColorTheme {
white,
normal,
light,
ultraLight
}
} }
@@ -1,11 +0,0 @@
package com.vk.extensions;
import android.widget.TextView;
import androidx.annotation.AttrRes;
import com.vk.core.ui.themes.VKThemeHelper;
public final class TextViewExt {
public static void a(TextView textView, @AttrRes int i) {
VKThemeHelper.a(textView, i);
}
}
@@ -31,6 +31,30 @@ public final class DialogGetMentionSuggestionCmd extends BaseImEngineCmd<Suggest
private final boolean e; private final boolean e;
private final Object f; private final Object f;
public static final class a<T> implements Comparator<Member> {
List a;
a(List list) {
this.a = list;
}
@Override // java.util.Comparator
/* renamed from: a */
public int compare(Member member, Member member2) {
int indexOf = this.a.indexOf(member);
int indexOf2 = this.a.indexOf(member2);
int i = indexOf;
if (indexOf < 0) {
i = Integer.MAX_VALUE;
}
int i2 = indexOf2;
if (indexOf2 < 0) {
i2 = Integer.MAX_VALUE;
}
return Intrinsics.a(i, i2);
}
}
public DialogGetMentionSuggestionCmd(int i, String str, Source source, boolean z, Object obj) { public DialogGetMentionSuggestionCmd(int i, String str, Source source, boolean z, Object obj) {
this.f2365b = i; this.f2365b = i;
this.c = str; this.c = str;
@@ -126,7 +150,7 @@ public final class DialogGetMentionSuggestionCmd extends BaseImEngineCmd<Suggest
Collection<Member> a2; Collection<Member> a2;
Source source; Source source;
if (ImDialogsUtils.d(this.f2365b) != PeerType.CHAT) { if (ImDialogsUtils.d(this.f2365b) != PeerType.CHAT) {
return new Suggestion(null, null); return new Suggestion((EntityValue) null, (ProfilesInfo) null);
} }
Member Z = imEnvironment.Z(); Member Z = imEnvironment.Z();
int d = imEnvironment.a0().n().d(); int d = imEnvironment.a0().n().d();
@@ -162,7 +186,8 @@ public final class DialogGetMentionSuggestionCmd extends BaseImEngineCmd<Suggest
} }
}), a(b2))); }), a(b2)));
EntityValue entityValue = new EntityValue(z2 ? null : l, z3); EntityValue entityValue = new EntityValue(z2 ? null : l, z3);
switch (this.d) { switch (this.d)
{
case CACHE: case CACHE:
source = Source.CACHE; source = Source.CACHE;
break; break;
@@ -211,28 +236,4 @@ public final class DialogGetMentionSuggestionCmd extends BaseImEngineCmd<Suggest
public String toString() { public String toString() {
return "DialogGetMentionSuggestionCmd(dialogId=" + this.f2365b + ", query=" + this.c + ", source=" + this.d + ", isAwaitNetwork=" + this.e + ", changerTag=" + this.f + ")"; return "DialogGetMentionSuggestionCmd(dialogId=" + this.f2365b + ", query=" + this.c + ", source=" + this.d + ", isAwaitNetwork=" + this.e + ", changerTag=" + this.f + ")";
} }
public static final class a<T> implements Comparator<Member> {
List a;
a(List list) {
this.a = list;
}
@Override // java.util.Comparator
/* renamed from: a */
public int compare(Member member, Member member2) {
int indexOf = this.a.indexOf(member);
int indexOf2 = this.a.indexOf(member2);
int i = indexOf;
if (indexOf < 0) {
i = Integer.MAX_VALUE;
}
int i2 = indexOf2;
if (indexOf2 < 0) {
i2 = Integer.MAX_VALUE;
}
return Intrinsics.a(i, i2);
}
}
} }
@@ -16,18 +16,12 @@ public enum MemberType {
public static MemberType a(int i) { public static MemberType a(int i) {
switch (i) { switch (i) {
case 0: case 0: return UNKNOWN;
return UNKNOWN; case 1: return USER;
case 1: case 2: return GROUP;
return USER; case 3: return EMAIL;
case 2: case 4: return CONTACT;
return GROUP; case 5: return CUSTOM_BOT;
case 3:
return EMAIL;
case 4:
return CONTACT;
case 5:
return CUSTOM_BOT;
} }
throw new IllegalArgumentException("Unknown member type value: " + i); throw new IllegalArgumentException("Unknown member type value: " + i);
} }
@@ -11,15 +11,16 @@ import com.vk.im.engine.models.dialogs.Dialog;
import com.vk.im.engine.models.groups.Group; import com.vk.im.engine.models.groups.Group;
import com.vk.im.engine.utils.DialogPermissionHelper; import com.vk.im.engine.utils.DialogPermissionHelper;
import com.vk.im.ui.p.ImBridge7; import com.vk.im.ui.p.ImBridge7;
import ru.vtosters.hooks.DialogMenuInjectors;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import ru.vtosters.lite.dnr.DNRInjector;
public final class DialogActionsHelper { public final class DialogActionsHelper {
public static final DialogActionsHelper a = new DialogActionsHelper(); public static final DialogActionsHelper a = new DialogActionsHelper();
public List<DialogAction> a(ImConfig imConfig, Dialog dialog, ProfilesSimpleInfo profilesSimpleInfo) { public final List<DialogAction> a(ImConfig imConfig, Dialog dialog, ProfilesSimpleInfo profilesSimpleInfo) {
if (dialog != null && profilesSimpleInfo != null) { if (dialog != null && profilesSimpleInfo != null) {
long b2 = TimeProvider.f.b(); long b2 = TimeProvider.f.b();
ChatSettings z1 = dialog.z1(); ChatSettings z1 = dialog.z1();
@@ -27,7 +28,7 @@ public final class DialogActionsHelper {
boolean I1 = z1 != null && z1.I1(); boolean I1 = z1 != null && z1.I1();
ArrayList<DialogAction> arrayList = new ArrayList<>(); ArrayList<DialogAction> arrayList = new ArrayList<>();
DialogMenuInjectors.inject(dialog, arrayList); DNRInjector.inject(dialog, arrayList);
arrayList.add(DialogAction.SEARCH); arrayList.add(DialogAction.SEARCH);
@@ -84,7 +85,7 @@ public final class DialogActionsHelper {
return new ArrayList<>(); return new ArrayList<>();
} }
public List<DialogAction> a(Dialog dialog, ProfilesSimpleInfo profilesSimpleInfo) { public final List<DialogAction> a(Dialog dialog, ProfilesSimpleInfo profilesSimpleInfo) {
long b2 = TimeProvider.f.b(); long b2 = TimeProvider.f.b();
Profile profile = profilesSimpleInfo.get(dialog.getId()); Profile profile = profilesSimpleInfo.get(dialog.getId());
@@ -96,7 +97,7 @@ public final class DialogActionsHelper {
ChatSettings z1 = dialog.z1(); ChatSettings z1 = dialog.z1();
ArrayList<DialogAction> arrayList = new ArrayList<>(); ArrayList<DialogAction> arrayList = new ArrayList<>();
DialogMenuInjectors.inject(dialog, arrayList); DNRInjector.inject(dialog, arrayList);
// if (dialog.hasUnread()) { // if (dialog.hasUnread()) {
arrayList.add(DialogAction.MARK_AS_READ); arrayList.add(DialogAction.MARK_AS_READ);
@@ -138,7 +139,7 @@ public final class DialogActionsHelper {
return arrayList; return arrayList;
} }
public boolean a(Dialog dialog) { public final boolean a(Dialog dialog) {
if (dialog.V1() || !dialog.y1()) { if (dialog.V1() || !dialog.y1()) {
return false; return false;
} }
@@ -11,6 +11,5 @@ public enum MsgAction {
PIN, PIN,
UNPIN, UNPIN,
TRANSLATE, TRANSLATE,
READTO, READTO
KICK
} }
@@ -3,11 +3,9 @@ package com.vk.im.ui.components.common;
import com.vk.core.extensions.CollectionExt; import com.vk.core.extensions.CollectionExt;
import com.vk.im.engine.ImConfig; import com.vk.im.engine.ImConfig;
import com.vk.im.engine.ImEngine; import com.vk.im.engine.ImEngine;
import com.vk.im.engine.models.Member;
import com.vk.im.engine.models.dialogs.Dialog; import com.vk.im.engine.models.dialogs.Dialog;
import com.vk.im.engine.models.messages.Msg; import com.vk.im.engine.models.messages.Msg;
import com.vk.im.engine.utils.MsgPermissionHelper; import com.vk.im.engine.utils.MsgPermissionHelper;
import ru.vtosters.lite.utils.AccountManagerUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@@ -16,11 +14,11 @@ import java.util.List;
public final class MsgActionHelper { public final class MsgActionHelper {
public static final MsgActionHelper a = new MsgActionHelper(); public static final MsgActionHelper a = new MsgActionHelper();
public List<MsgAction> a(ImEngine imEngine, Dialog dialog, Collection<? extends Msg> collection) { public final List<MsgAction> a(ImEngine imEngine, Dialog dialog, Collection<? extends Msg> collection) {
return a(imEngine != null ? imEngine.g() : null, dialog, collection); return a(imEngine != null ? imEngine.g() : null, dialog, collection);
} }
public List<MsgAction> a(ImConfig imConfig, Dialog dialog, Collection<? extends Msg> collection) { public final List<MsgAction> a(ImConfig imConfig, Dialog dialog, Collection<? extends Msg> collection) {
if (imConfig != null && dialog != null && collection != null) { if (imConfig != null && dialog != null && collection != null) {
MsgPermissionHelper.a aVar = new MsgPermissionHelper.a(imConfig, dialog, collection); MsgPermissionHelper.a aVar = new MsgPermissionHelper.a(imConfig, dialog, collection);
ArrayList<MsgAction> arrayList = new ArrayList<>(); ArrayList<MsgAction> arrayList = new ArrayList<>();
@@ -37,24 +35,6 @@ public final class MsgActionHelper {
CollectionExt.a(arrayList, MsgAction.TRANSLATE, true); CollectionExt.a(arrayList, MsgAction.TRANSLATE, true);
CollectionExt.a(arrayList, MsgAction.READTO, true); CollectionExt.a(arrayList, MsgAction.READTO, true);
boolean isAdmin = false;
try {
if (aVar.a().z1().L0().t1() == AccountManagerUtils.getUserId()) { // is owner
isAdmin = true;
} else if (!aVar.a().z1().K1()) { // is you not kicked
for (Member admins : aVar.a().z1().t1()) { // admin list
if (admins.t1() == AccountManagerUtils.getUserId()) {
isAdmin = true;
break;
}
}
}
} catch (Exception ignored) {
}
CollectionExt.a(arrayList, MsgAction.KICK, isAdmin);
return arrayList; return arrayList;
} }
@@ -21,7 +21,6 @@ import com.vk.im.ui.q.h.VideoAutoPlayer;
import com.vk.im.ui.views.span.OnSpanClickListener; import com.vk.im.ui.views.span.OnSpanClickListener;
import com.vk.im.ui.views.span.OnSpanLongPressListener; import com.vk.im.ui.views.span.OnSpanLongPressListener;
import com.vk.im.ui.views.sticker.StickerAnimationState; import com.vk.im.ui.views.sticker.StickerAnimationState;
import java.util.List; import java.util.List;
@MainThread @MainThread
@@ -17,7 +17,11 @@ import com.vk.im.engine.models.ProfilesSimpleInfo;
import com.vk.im.engine.models.attaches.AttachAudioMsg; import com.vk.im.engine.models.attaches.AttachAudioMsg;
import com.vk.im.engine.models.dialogs.Dialog; import com.vk.im.engine.models.dialogs.Dialog;
import com.vk.im.engine.models.dialogs.DialogTheme; import com.vk.im.engine.models.dialogs.DialogTheme;
import com.vk.im.engine.models.messages.*; import com.vk.im.engine.models.messages.Msg;
import com.vk.im.engine.models.messages.MsgFromUser;
import com.vk.im.engine.models.messages.MsgIdType;
import com.vk.im.engine.models.messages.MsgSyncState;
import com.vk.im.engine.models.messages.WithUserContent;
import com.vk.im.engine.utils.collection.IntSet; import com.vk.im.engine.utils.collection.IntSet;
import com.vk.im.ui.components.viewcontrollers.msg_list.entry.AdapterEntry; import com.vk.im.ui.components.viewcontrollers.msg_list.entry.AdapterEntry;
import com.vk.im.ui.media.audio.AudioTrack; import com.vk.im.ui.media.audio.AudioTrack;
@@ -74,7 +78,11 @@ public class VhBindArgs {
private boolean L() { private boolean L() {
boolean var1; boolean var1;
var1 = this.K() > this.m || TimeProvider.f.c(); if (this.K() <= this.m && !TimeProvider.f.c()) {
var1 = false;
} else {
var1 = true;
}
return var1; return var1;
} }
@@ -105,7 +113,11 @@ public class VhBindArgs {
public boolean B() { public boolean B() {
AdapterEntry var1 = this.a; AdapterEntry var1 = this.a;
boolean var2; boolean var2;
var2 = var1 != null && var1.c(); if (var1 != null && var1.c()) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -113,7 +125,11 @@ public class VhBindArgs {
public boolean C() { public boolean C() {
AdapterEntry var1 = this.a; AdapterEntry var1 = this.a;
boolean var2; boolean var2;
var2 = var1 != null && var1.c() && this.a.c.getLocalId() == this.b.c.getLocalId(); if (var1 != null && var1.c() && this.a.c.getLocalId() == this.b.c.getLocalId()) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -121,7 +137,11 @@ public class VhBindArgs {
public boolean D() { public boolean D() {
AdapterEntry var1 = this.a; AdapterEntry var1 = this.a;
boolean var2; boolean var2;
var2 = var1 != null && var1.a == 83; if (var1 != null && var1.a == 83) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -129,7 +149,11 @@ public class VhBindArgs {
public boolean E() { public boolean E() {
Msg var1 = this.b.c; Msg var1 = this.b.c;
boolean var2; boolean var2;
var2 = var1 instanceof MsgFromUser && ((MsgFromUser) var1).i2(); if (var1 instanceof MsgFromUser && ((MsgFromUser)var1).i2()) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -137,7 +161,11 @@ public class VhBindArgs {
public boolean F() { public boolean F() {
Msg var1 = this.b.c; Msg var1 = this.b.c;
boolean var2; boolean var2;
var2 = var1 instanceof MsgFromUser && ((MsgFromUser) var1).F0(); if (var1 instanceof MsgFromUser && ((MsgFromUser)var1).F0()) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -145,7 +173,11 @@ public class VhBindArgs {
public boolean G() { public boolean G() {
AdapterEntry var1 = this.b; AdapterEntry var1 = this.b;
boolean var2; boolean var2;
var2 = var1 != null && var1.a == 51; if (var1 != null && var1.a == 51) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -158,7 +190,11 @@ public class VhBindArgs {
long var1 = this.K(); long var1 = this.K();
long var3 = this.m; long var3 = this.m;
boolean var5; boolean var5;
var5 = var1 > var3 && var1 < var3 * 2L; if (var1 > var3 && var1 < var3 * 2L) {
var5 = true;
} else {
var5 = false;
}
return var5; return var5;
} }
@@ -171,13 +207,21 @@ public class VhBindArgs {
} else if (!(var1 instanceof MsgFromUser)) { } else if (!(var1 instanceof MsgFromUser)) {
return false; return false;
} else { } else {
MsgFromUser var7 = (MsgFromUser) var1; MsgFromUser var7 = (MsgFromUser)var1;
Msg var3 = this.a.c; Msg var3 = this.a.c;
boolean var4; boolean var4;
var4 = var3 != null && var3.d() == MsgSyncState.DONE; if (var3 != null && var3.d() == MsgSyncState.DONE) {
var4 = true;
} else {
var4 = false;
}
boolean var5; boolean var5;
var5 = this.o == ImBgSyncState.CONNECTED; if (this.o == ImBgSyncState.CONNECTED) {
var5 = true;
} else {
var5 = false;
}
boolean var6 = var2; boolean var6 = var2;
if (!var7.H0()) { if (!var7.H0()) {
@@ -202,7 +246,7 @@ public class VhBindArgs {
byte var2 = 0; byte var2 = 0;
int var3 = var2; int var3 = var2;
if (var1) { if (var1) {
AttachAudioMsg var4 = ((MsgFromUser) this.b.c).c(AttachAudioMsg.class, false); AttachAudioMsg var4 = (AttachAudioMsg)((MsgFromUser)this.b.c).c(AttachAudioMsg.class, false);
var3 = var2; var3 = var2;
if (var4 != null) { if (var4 != null) {
var3 = var4.f(); var3 = var4.f();
@@ -227,7 +271,11 @@ public class VhBindArgs {
public boolean c() { public boolean c() {
Msg var1 = this.b.c; Msg var1 = this.b.c;
boolean var2; boolean var2;
var2 = var1 instanceof MsgFromUser && ((MsgFromUser) var1).I0(); if (var1 instanceof MsgFromUser && ((MsgFromUser)var1).I0()) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -235,14 +283,22 @@ public class VhBindArgs {
public boolean d() { public boolean d() {
Msg var1 = this.b.c; Msg var1 = this.b.c;
boolean var2; boolean var2;
var2 = var1 instanceof WithUserContent && ((WithUserContent) var1).D0() != null; if (var1 instanceof WithUserContent && ((WithUserContent)var1).D0() != null) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
public boolean e() { public boolean e() {
boolean var1; boolean var1;
var1 = this.b.i > 0; if (this.b.i > 0) {
var1 = true;
} else {
var1 = false;
}
return var1; return var1;
} }
@@ -265,7 +321,11 @@ public class VhBindArgs {
public boolean g() { public boolean g() {
Msg var1 = this.b.c; Msg var1 = this.b.c;
boolean var2; boolean var2;
var2 = var1 instanceof MsgFromUser && ((MsgFromUser) var1).G0(); if (var1 instanceof MsgFromUser && ((MsgFromUser)var1).G0()) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -273,21 +333,33 @@ public class VhBindArgs {
public boolean h() { public boolean h() {
Msg var1 = this.b.c; Msg var1 = this.b.c;
boolean var2; boolean var2;
var2 = var1 instanceof MsgFromUser && ((MsgFromUser) var1).Z1(); if (var1 instanceof MsgFromUser && ((MsgFromUser)var1).Z1()) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
public boolean i() { public boolean i() {
boolean var1; boolean var1;
var1 = this.j && !this.u() && !this.l(); if (this.j && !this.u() && !this.l()) {
var1 = true;
} else {
var1 = false;
}
return var1; return var1;
} }
public boolean j() { public boolean j() {
boolean var1; boolean var1;
var1 = this.j && !this.u() && (!this.B() || !this.A() || this.a.c.H1()); if (!this.j || this.u() || this.B() && this.A() && !this.a.c.H1()) {
var1 = false;
} else {
var1 = true;
}
return var1; return var1;
} }
@@ -295,7 +367,11 @@ public class VhBindArgs {
public boolean k() { public boolean k() {
Dialog var1 = this.e; Dialog var1 = this.e;
boolean var2; boolean var2;
var2 = var1 != null && var1.U1(); if (var1 != null && var1.U1()) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -303,7 +379,11 @@ public class VhBindArgs {
public boolean l() { public boolean l() {
Dialog var1 = this.e; Dialog var1 = this.e;
boolean var2; boolean var2;
var2 = var1 != null && var1.V1(); if (var1 != null && var1.V1()) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -311,7 +391,11 @@ public class VhBindArgs {
public boolean m() { public boolean m() {
Dialog var1 = this.e; Dialog var1 = this.e;
boolean var2; boolean var2;
var2 = var1 != null && var1.W1(); if (var1 != null && var1.W1()) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -324,7 +408,11 @@ public class VhBindArgs {
public boolean o() { public boolean o() {
AdapterEntry var1 = this.b; AdapterEntry var1 = this.b;
boolean var2; boolean var2;
var2 = var1 != null && var1.a == 101; if (var1 != null && var1.a == 101) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -332,7 +420,11 @@ public class VhBindArgs {
public boolean p() { public boolean p() {
Msg var1 = this.b.c; Msg var1 = this.b.c;
boolean var2; boolean var2;
var2 = var1 != null && var1.G1(); if (var1 != null && var1.G1()) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -355,13 +447,17 @@ public class VhBindArgs {
public boolean r() { public boolean r() {
Msg var1 = this.b.c; Msg var1 = this.b.c;
boolean var2; boolean var2;
var2 = var1 instanceof MsgFromUser && ((MsgFromUser) var1).e2(); if (var1 instanceof MsgFromUser && ((MsgFromUser)var1).e2()) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
public boolean s() { public boolean s() {
if (this.C != null) if(this.C != null)
return switch (this.C) { return switch (this.C) {
case LOCAL_ID -> this.D == this.b.c.getLocalId(); case LOCAL_ID -> this.D == this.b.c.getLocalId();
case VK_ID -> this.D == this.b.c.C1(); case VK_ID -> this.D == this.b.c.C1();
@@ -396,19 +492,27 @@ public class VhBindArgs {
public boolean v() { public boolean v() {
IntSet var1 = this.r; IntSet var1 = this.r;
boolean var2; boolean var2;
var2 = var1 != null && var1.a(this.b.c.getLocalId()); if (var1 != null && var1.a(this.b.c.getLocalId())) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
public boolean w() { public boolean w() {
return !this.z(); return this.z() ^ true;
} }
public boolean x() { public boolean x() {
AdapterEntry var1 = this.c; AdapterEntry var1 = this.c;
boolean var2; boolean var2;
var2 = var1 != null && var1.a == 100; if (var1 != null && var1.a == 100) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -416,7 +520,11 @@ public class VhBindArgs {
public boolean y() { public boolean y() {
AdapterEntry var1 = this.c; AdapterEntry var1 = this.c;
boolean var2; boolean var2;
var2 = var1 != null && var1.a == 96; if (var1 != null && var1.a == 96) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -424,7 +532,11 @@ public class VhBindArgs {
public boolean z() { public boolean z() {
AdapterEntry var1 = this.c; AdapterEntry var1 = this.c;
boolean var2; boolean var2;
var2 = var1 != null && var1.c() && this.c.c.getLocalId() == this.b.c.getLocalId(); if (var1 != null && var1.c() && this.c.c.getLocalId() == this.b.c.getLocalId()) {
var2 = true;
} else {
var2 = false;
}
return var2; return var2;
} }
@@ -21,7 +21,7 @@ import com.vk.im.ui.views.msg.MsgPartIconTwoRowView;
import com.vtosters.lite.R; import com.vtosters.lite.R;
import kotlin.TypeCastException; import kotlin.TypeCastException;
import kotlin.jvm.internal.Intrinsics; import kotlin.jvm.internal.Intrinsics;
import ru.vtosters.hooks.CallsHook; import ru.vtosters.lite.hooks.CallsHook;
public final class MsgPartCallHolder extends MsgPartHolderBase<AttachCall> { public final class MsgPartCallHolder extends MsgPartHolderBase<AttachCall> {
public static final a I = new a(); public static final a I = new a();
@@ -46,7 +46,7 @@ public final class MsgPartCallHolder extends MsgPartHolderBase<AttachCall> {
this.G = new StringBuilder(); this.G = new StringBuilder();
} }
private void a(Msg var1) { private final void a(Msg var1) {
this.G.setLength(0); this.G.setLength(0);
MsgTimeFormatter var2 = this.F; MsgTimeFormatter var2 = this.F;
Context var3 = this.C; Context var3 = this.C;
@@ -55,7 +55,7 @@ public final class MsgPartCallHolder extends MsgPartHolderBase<AttachCall> {
this.H.setTimeText(this.G); this.H.setTimeText(this.G);
} }
private void a(boolean var1) { private final void a(boolean var1) {
MsgPartIconTwoRowView var2 = this.H; MsgPartIconTwoRowView var2 = this.H;
int var3; int var3;
if (var1) { if (var1) {
@@ -67,7 +67,7 @@ public final class MsgPartCallHolder extends MsgPartHolderBase<AttachCall> {
var2.setIcon(var3); var2.setIcon(var3);
} }
private void a(boolean var1, AttachCall var2) { private final void a(boolean var1, AttachCall var2) {
boolean var3 = !var1; boolean var3 = !var1;
if (var2.h() == CallState.ERROR) { if (var2.h() == CallState.ERROR) {
this.H.setSubtitleText(m.vkim_msg_list_call_error); this.H.setSubtitleText(m.vkim_msg_list_call_error);
@@ -23,7 +23,7 @@ public class MsgPartTextHolder extends MsgPartHolderBase<Attach> {
MsgPartTextHolder.this.f.a(MsgPartTextHolder.this.g.getLocalId()); MsgPartTextHolder.this.f.a(MsgPartTextHolder.this.g.getLocalId());
}); });
mTextPart.setOnLongClickListener(view -> { mTextPart.setOnLongClickListener(view -> {
if (!mTextPart.isTextSelectable()) MsgPartTextHolder.this.f.b(MsgPartTextHolder.this.g.getLocalId()); if(!mTextPart.isTextSelectable()) MsgPartTextHolder.this.f.b(MsgPartTextHolder.this.g.getLocalId());
return false; return false;
}); });
@@ -28,6 +28,7 @@ import com.vk.im.engine.models.Profile;
import com.vk.im.engine.models.dialogs.BubbleColors; import com.vk.im.engine.models.dialogs.BubbleColors;
import com.vk.im.engine.models.dialogs.Dialog; import com.vk.im.engine.models.dialogs.Dialog;
import com.vk.im.engine.models.messages.Msg; import com.vk.im.engine.models.messages.Msg;
import com.vk.im.engine.models.messages.MsgSyncState;
import com.vk.im.engine.utils.MsgPermissionHelper; import com.vk.im.engine.utils.MsgPermissionHelper;
import com.vk.im.ui.components.viewcontrollers.msg_list.BombView; import com.vk.im.ui.components.viewcontrollers.msg_list.BombView;
import com.vk.im.ui.components.viewcontrollers.msg_list.SwipeToReplyItemTouchCallback; import com.vk.im.ui.components.viewcontrollers.msg_list.SwipeToReplyItemTouchCallback;
@@ -49,7 +50,6 @@ import com.vk.im.ui.views.msg.bubble.MsgBubbleView;
import com.vk.im.ui.views.sticker.StickerAnimationState; import com.vk.im.ui.views.sticker.StickerAnimationState;
import kotlin.Unit; import kotlin.Unit;
import kotlin.jvm.b.Functions; import kotlin.jvm.b.Functions;
import ru.vtosters.lite.themes.ThemesHacks;
public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b { public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
public static final int h0 = Screen.a(124); public static final int h0 = Screen.a(124);
@@ -57,6 +57,46 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
private static final int[][] j0; private static final int[][] j0;
private static final int[][] k0; private static final int[][] k0;
private static final int[][] l0; private static final int[][] l0;
private final MsgPartHolderBase B;
private final MsgPartHolderBindArgs C = new MsgPartHolderBindArgs();
private final Rect D = new Rect();
private final Rect E = new Rect();
private final Rect F = new Rect();
private final Rect G = new Rect();
private ColorDrawable H;
private final int I;
private final int J;
private final int K;
private final int L;
private final int M;
private Drawable N;
private Drawable O;
private BombView P;
private BombView.d Q;
private int R;
private int S;
private final DisplayNameFormatter T = new DisplayNameFormatter();
private final StringBuilder U = new StringBuilder();
private final StringBuilder V = new StringBuilder();
private final String W;
private final String X;
private final String Y;
private boolean Z;
private BubbleColors a0;
private final FluidHorizontalLayout b;
@ColorInt
private int b0;
private final AvatarView c;
private MsgListAdapterCallback c0;
private final Space d;
private Msg d0;
private final MsgBubbleView e;
private Dialog e0;
private final MsgStatusView f;
private int f0;
private final ImageView g;
private h g0 = new h();
private final Space h;
static { static {
int[] var0 = new int[]{0, 0, 0, 0}; int[] var0 = new int[]{0, 0, 0, 0};
@@ -80,61 +120,20 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
l0 = new int[][]{var0, {4, 4, 0, 0, 0, 2, 8, 0}, var1, var2, {4, 0, 0, 0, 0, 2, 8, 0}, {0, 0, 0, 0, 0, 2, 8, 0}, {4, 4, 0, 0, 0, 2, 8, 0}, {0, 0, 0, 0, 0, 0, 0, 0}}; l0 = new int[][]{var0, {4, 4, 0, 0, 0, 2, 8, 0}, var1, var2, {4, 0, 0, 0, 0, 2, 8, 0}, {0, 0, 0, 0, 0, 2, 8, 0}, {4, 4, 0, 0, 0, 2, 8, 0}, {0, 0, 0, 0, 0, 0, 0, 0}};
} }
private final MsgPartHolderBase B;
private final MsgPartHolderBindArgs C = new MsgPartHolderBindArgs();
private final Rect D = new Rect();
private final Rect E = new Rect();
private final Rect F = new Rect();
private final Rect G = new Rect();
private final int I;
private final int J;
private final int K;
private final int L;
private final int M;
private final DisplayNameFormatter T = new DisplayNameFormatter();
private final StringBuilder U = new StringBuilder();
private final StringBuilder V = new StringBuilder();
private final String W;
private final String X;
private final String Y;
private final FluidHorizontalLayout b;
private final AvatarView c;
private final Space d;
private final MsgBubbleView e;
private final MsgStatusView f;
private final ImageView g;
private final Space h;
private final ColorDrawable H;
private Drawable N;
private Drawable O;
private final BombView P;
private final BombView.d Q;
private final int R;
private final int S;
private boolean Z;
private BubbleColors a0;
@ColorInt
private int b0;
private MsgListAdapterCallback c0;
private Msg d0;
private Dialog e0;
private int f0;
private final h g0 = new h();
public VhMsg(View itemView, MsgPartHolderBase vhBase) { public VhMsg(View itemView, MsgPartHolderBase vhBase) {
super(itemView); super(itemView);
Context context = itemView.getContext(); Context context = itemView.getContext();
LayoutInflater var4 = LayoutInflater.from(context); LayoutInflater var4 = LayoutInflater.from(context);
this.b = (FluidHorizontalLayout) itemView; this.b = (FluidHorizontalLayout) itemView;
this.c = itemView.findViewById(com.vk.im.ui.h.avatar); this.c = (AvatarView) itemView.findViewById(com.vk.im.ui.h.avatar);
this.d = itemView.findViewById(com.vk.im.ui.h.avatar_space); this.d = (Space) itemView.findViewById(com.vk.im.ui.h.avatar_space);
this.e = itemView.findViewById(com.vk.im.ui.h.bubble); this.e = (MsgBubbleView) itemView.findViewById(com.vk.im.ui.h.bubble);
this.f = itemView.findViewById(com.vk.im.ui.h.status); this.f = (MsgStatusView) itemView.findViewById(com.vk.im.ui.h.status);
this.g = itemView.findViewById(com.vk.im.ui.h.vkim_channel_share); this.g = (ImageView) itemView.findViewById(com.vk.im.ui.h.vkim_channel_share);
this.h = itemView.findViewById(com.vk.im.ui.h.status_space); this.h = (Space) itemView.findViewById(com.vk.im.ui.h.status_space);
this.P = itemView.findViewById(com.vk.im.ui.h.bomb); this.P = (BombView) itemView.findViewById(com.vk.im.ui.h.bomb);
this.B = vhBase; this.B = vhBase;
this.H = new ColorDrawable(ThemesHacks.getColors(context, com.vk.im.ui.d.msg_search_selection)); this.H = new ColorDrawable(context.getResources().getColor(com.vk.im.ui.d.msg_search_selection));
this.I = ContextExtKt.b(context, com.vk.im.ui.e.msg_bubble_max_width); this.I = ContextExtKt.b(context, com.vk.im.ui.e.msg_bubble_max_width);
this.J = ContextExtKt.b(context, com.vk.im.ui.e.msg_reply_max_width); this.J = ContextExtKt.b(context, com.vk.im.ui.e.msg_reply_max_width);
this.K = ContextExtKt.b(context, com.vk.im.ui.e.msg_sticker_max_width); this.K = ContextExtKt.b(context, com.vk.im.ui.e.msg_sticker_max_width);
@@ -145,44 +144,54 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
this.X = context.getString(m.vkim_accessibility_msg_unread); this.X = context.getString(m.vkim_accessibility_msg_unread);
MsgBubbleView var5 = this.e; MsgBubbleView var5 = this.e;
var5.setContentView(this.B.a(var4, var5)); var5.setContentView(this.B.a(var4, var5));
ViewGroup.MarginLayoutParams var7 = (ViewGroup.MarginLayoutParams) this.e.getLayoutParams(); ViewGroup.MarginLayoutParams var7 = (ViewGroup.MarginLayoutParams)this.e.getLayoutParams();
Rect var6 = this.G; Rect var6 = this.G;
var6.left = var7.leftMargin; var6.left = var7.leftMargin;
var6.right = var7.rightMargin; var6.right = var7.rightMargin;
var6.top = var7.topMargin; var6.top = var7.topMargin;
var6.bottom = var7.bottomMargin; var6.bottom = var7.bottomMargin;
ViewExtKt.b(this.c, var1 -> { ViewExtKt.b(this.c, new View.OnClickListener() {
public void onClick(View var1) {
if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) { if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) {
VhMsg.this.c0.a(VhMsg.this.d0.getFrom()); VhMsg.this.c0.a(VhMsg.this.d0.getFrom());
} }
}
}); });
this.c.setOnLongClickListener(var1 -> { this.c.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View var1) {
if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) { if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) {
VhMsg.this.c0.a(VhMsg.this.d0.getFrom()); VhMsg.this.c0.a(VhMsg.this.d0.getFrom());
return true; return true;
} else { } else {
return false; return false;
} }
}
}); });
ViewExtKt.b(this.g, var1 -> { ViewExtKt.b(this.g, new View.OnClickListener() {
public void onClick(View var1) {
if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) { if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) {
VhMsg.this.c0.a(VhMsg.this.d0); VhMsg.this.c0.a(VhMsg.this.d0);
} }
}
}); });
ViewExtKt.b(this.itemView, (View.OnClickListener) var1 -> { ViewExtKt.b(this.itemView, new View.OnClickListener() {
public void onClick(View var1) {
if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) { if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) {
VhMsg.this.c0.a(VhMsg.this.d0.getLocalId()); VhMsg.this.c0.a(VhMsg.this.d0.getLocalId());
} }
}
}); });
this.itemView.setOnLongClickListener((View.OnLongClickListener) var1 -> { this.itemView.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View var1) {
if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) { if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) {
VhMsg.this.c0.b(VhMsg.this.d0.getLocalId()); VhMsg.this.c0.b(VhMsg.this.d0.getLocalId());
} }
return true; return true;
}
}); });
this.R = ContextExtKt.i(context, com.vk.im.ui.c.im_msg_part_corner_radius_small); this.R = ContextExtKt.i(context, com.vk.im.ui.c.im_msg_part_corner_radius_small);
this.S = ContextExtKt.i(context, com.vk.im.ui.c.im_msg_part_corner_radius_big); this.S = ContextExtKt.i(context, com.vk.im.ui.c.im_msg_part_corner_radius_big);
@@ -195,10 +204,6 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
}; };
} }
public static VhMsg a(LayoutInflater var0, ViewGroup var1, MsgPartHolderBase var2) {
return new VhMsg(var0.inflate(j.vkim_msg_list_item_msg_from_user, var1, false), var2);
}
private int a(Style var1, Style var2, boolean var3) { private int a(Style var1, Style var2, boolean var3) {
int var4; int var4;
if (var3) { if (var3) {
@@ -279,15 +284,20 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
case 103: case 103:
return VhMsg.Style.EMPTY; return VhMsg.Style.EMPTY;
default: default:
String var3 = "Unknown viewType: " + StringBuilder var3 = new StringBuilder();
var1; var3.append("Unknown viewType: ");
throw new IllegalArgumentException(var3); var3.append(var1);
throw new IllegalArgumentException(var3.toString());
} }
} }
return VhMsg.Style.TWO_LINE; return VhMsg.Style.TWO_LINE;
} }
public static VhMsg a(LayoutInflater var0, ViewGroup var1, MsgPartHolderBase var2) {
return new VhMsg(var0.inflate(j.vkim_msg_list_item_msg_from_user, var1, false), var2);
}
private void a(VhBindArgs args, Rect rect) { private void a(VhBindArgs args, Rect rect) {
Style var3 = this.a(args.b); Style var3 = this.a(args.b);
boolean var4 = args.b.f(); boolean var4 = args.b.f();
@@ -327,8 +337,7 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
if (args.w()) { if (args.w()) {
var12 = var11; var12 = var11;
if (args.k()) { if (args.k()) {
label30: label30: {
{
if (args.G()) { if (args.G()) {
var12 = Screen.a(4); var12 = Screen.a(4);
} else { } else {
@@ -402,7 +411,11 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
Msg var10 = var5.c; Msg var10 = var5.c;
var9 = var6; var9 = var6;
if (var10 != null) { if (var10 != null) {
var9 = var10.v1() == args.g.t1(); if (var10.v1() == args.g.t1()) {
var9 = true;
} else {
var9 = false;
}
if (var10.O1()) { if (var10.O1()) {
int var12 = var10.d().ordinal(); int var12 = var10.d().ordinal();
@@ -420,7 +433,11 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
b = args.I(); b = args.I();
} }
} else { } else {
var6 = var10.C1() <= args.i; if (var10.C1() <= args.i) {
var6 = true;
} else {
var6 = false;
}
if (!var6 && !var9) { if (!var6 && !var9) {
var11 = MsgStatus.UNREAD; var11 = MsgStatus.UNREAD;
@@ -558,14 +575,18 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
partArgs.o = args.n; partArgs.o = args.n;
partArgs.s = args.v(); partArgs.s = args.v();
partArgs.t = args.q; partArgs.t = args.q;
partArgs.u = !var4.b(); partArgs.u = var4.b() ^ true;
boolean var5; boolean var5;
var5 = var3.i > 0; if (var3.i > 0) {
var5 = true;
} else {
var5 = false;
}
partArgs.v = var5; partArgs.v = var5;
partArgs.w = args.k; partArgs.w = args.k;
partArgs.x = args.l; partArgs.x = args.l;
partArgs.y = !this.Z; partArgs.y = this.Z ^ true;
partArgs.z = args.s; partArgs.z = args.s;
partArgs.A = args.t; partArgs.A = args.t;
partArgs.l = this.b0; partArgs.l = this.b0;
@@ -650,7 +671,7 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
private void f(VhBindArgs args) { private void f(VhBindArgs args) {
Msg var2 = args.b.c; Msg var2 = args.b.c;
if (var2 != null) { if (var2 != null) {
this.P.setStateListener(null); this.P.setStateListener((BombView.d)null);
if (var2.M1() && !var2.E1()) { if (var2.M1() && !var2.E1()) {
this.P.setVisibility(View.GONE); this.P.setVisibility(View.GONE);
} else { } else {
@@ -789,18 +810,29 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
this.e.setFwdPadding(this.D); this.e.setFwdPadding(this.D);
this.e.setContentPadding(this.E); this.e.setContentPadding(this.E);
boolean var7; boolean var7;
var7 = args.b.a == 83; if (args.b.a == 83) {
var7 = true;
} else {
var7 = false;
}
boolean var5; boolean var5;
var5 = args.a.a == 83; if (args.a.a == 83) {
var5 = true;
} else {
var5 = false;
}
var5 = !args.F() || !var7 && !var5; if (!args.F() || !var7 && !var5) {
var5 = true;
} else {
var5 = false;
}
MsgBubbleView var8 = this.e; MsgBubbleView var8 = this.e;
boolean var6 = var4; boolean var6 = var4;
if (var5) { if (var5) {
label57: label57: {
{
if (!args.C()) { if (!args.C()) {
var6 = var4; var6 = var4;
if (!args.z()) { if (!args.z()) {
@@ -845,7 +877,7 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
if (args.s()) { if (args.s()) {
this.itemView.setBackground(this.H); this.itemView.setBackground(this.H);
} else { } else {
this.itemView.setBackground((Drawable) null); this.itemView.setBackground((Drawable)null);
} }
} }
@@ -871,10 +903,18 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
return false; return false;
} else { } else {
boolean var5; boolean var5;
var5 = var2.a == 50; if (var2.a == 50) {
var5 = true;
} else {
var5 = false;
}
boolean var6; boolean var6;
var6 = !args.z() && var2.i == 0; if (!args.z() && var2.i == 0) {
var6 = true;
} else {
var6 = false;
}
if (var5 || var6 || args.y() || args.x()) { if (var5 || var6 || args.y() || args.x()) {
var4 = true; var4 = true;
@@ -893,7 +933,11 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
private boolean u(int var1) { private boolean u(int var1) {
boolean var2; boolean var2;
var2 = var1 == 2 || var1 == 3; if (var1 != 2 && var1 != 3) {
var2 = false;
} else {
var2 = true;
}
return var2; return var2;
} }
@@ -915,7 +959,9 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
Msg var1 = this.d0; Msg var1 = this.d0;
if (var1 != null) { if (var1 != null) {
Dialog var2 = this.e0; Dialog var2 = this.e0;
return var2 != null && MsgPermissionHelper.b.a(var2, var1); if (var2 != null && MsgPermissionHelper.b.a(var2, var1)) {
return true;
}
} }
} }
return false; return false;
@@ -939,7 +985,7 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
public void a(@NonNull Msg var1, int var2) { public void a(@NonNull Msg var1, int var2) {
if (this.f0()) { if (this.f0()) {
((MsgPartCarouselHolder) this.B).a(var1, var2); ((MsgPartCarouselHolder)this.B).a(var1, var2);
} }
} }
@@ -950,7 +996,11 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
public void a(VhBindArgs args) { public void a(VhBindArgs args) {
boolean var2; boolean var2;
var2 = VKThemeHelper.l() == VKTheme.VKAPP_LIGHT; if (VKThemeHelper.l() == VKTheme.VKAPP_LIGHT) {
var2 = true;
} else {
var2 = false;
}
this.Z = var2; this.Z = var2;
AdapterEntry var3 = args.b; AdapterEntry var3 = args.b;
@@ -1011,7 +1061,11 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
public boolean f0() { public boolean f0() {
boolean var1; boolean var1;
var1 = this.f0 == 100; if (this.f0 == 100) {
var1 = true;
} else {
var1 = false;
}
return var1; return var1;
} }
@@ -1028,7 +1082,7 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
this.B.c(var1); this.B.c(var1);
} }
private enum Style { private static enum Style {
BUTTON(6), BUTTON(6),
EMPTY(7), EMPTY(7),
FWD_SENDER(4), FWD_SENDER(4),
@@ -1040,14 +1094,14 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
public final int index; public final int index;
Style(int var3) { private Style(int var3) {
this.index = var3; this.index = var3;
} }
} }
private class h implements Functions<Unit> { private class h implements Functions<Unit> {
private final int a; private int a;
private final Runnable b; private Runnable b;
private h() { private h() {
this.a = Screen.a(12); this.a = Screen.a(12);
@@ -1056,7 +1110,7 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
public Unit invoke() { public Unit invoke() {
if (VhMsg.this.e.getMeasuredWidth() < VhMsg.h0) { if (VhMsg.this.e.getMeasuredWidth() < VhMsg.h0) {
((ViewGroup.MarginLayoutParams) VhMsg.this.e.getLayoutParams()).leftMargin = VhMsg.h0 - VhMsg.this.e.getMeasuredWidth() + this.a; ((ViewGroup.MarginLayoutParams)VhMsg.this.e.getLayoutParams()).leftMargin = VhMsg.h0 - VhMsg.this.e.getMeasuredWidth() + this.a;
VhMsg.this.e.invalidate(); VhMsg.this.e.invalidate();
VhMsg.this.e.requestLayout(); VhMsg.this.e.requestLayout();
} else { } else {
@@ -6,6 +6,7 @@ import android.os.Bundle;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewStub; import android.view.ViewStub;
import android.widget.TextView;
import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.vk.core.ui.VkBottomSheetBehavior; import com.vk.core.ui.VkBottomSheetBehavior;
@@ -26,28 +27,35 @@ import com.vtosters.lite.R;
public final class MentionsController { public final class MentionsController {
private final RichEditText a; private final RichEditText a;
private final ImEngine mImEngine;
private final View j;
private final b k;
private boolean state; private boolean state;
private CoordinatorLayout mCoordinatorLayout; private CoordinatorLayout mCoordinatorLayout;
private VkBottomSheetBehavior<RecyclerView> mBottomSheetBehavior; private VkBottomSheetBehavior<RecyclerView> mBottomSheetBehavior;
private boolean e; private boolean e;
private final DialogMentionComponent mDialogMentionComponent; private DialogMentionComponent mDialogMentionComponent;
private final MentionsManager mMentionsManager; private MentionsManager mMentionsManager;
private final int i; private final ImEngine mImEngine;
private int i;
private final View j;
private final b k;
public interface b {
boolean c();
boolean d();
}
public MentionsController(ImEngine imEngine, int i, View view, b bVar) { public MentionsController(ImEngine imEngine, int i, View view, b bVar) {
this.mImEngine = imEngine; this.mImEngine = imEngine;
this.i = i; this.i = i;
this.j = view; this.j = view;
this.k = bVar; this.k = bVar;
this.a = this.j.findViewById(R.id.writebar_edit); this.a = (RichEditText) this.j.findViewById(R.id.writebar_edit);
this.mMentionsManager = new MentionsManager(this.a, new MentionSuggestionsSupplier() { this.mMentionsManager = new MentionsManager(this.a, new MentionSuggestionsSupplier() {
@Override @Override
public boolean a() { public boolean a() {
if (MentionsController.this.state) if(MentionsController.this.state)
return ViewExtKt.i(MentionsController.this.mCoordinatorLayout); return ViewExtKt.i(MentionsController.this.mCoordinatorLayout);
return false; return false;
} }
@@ -64,7 +72,7 @@ public final class MentionsController {
@Override @Override
public void b() { public void b() {
MentionsController.this.mDialogMentionComponent.a(0, null); MentionsController.this.mDialogMentionComponent.a(0, (String) null);
MentionsController.this.g(); MentionsController.this.g();
} }
}); });
@@ -85,19 +93,19 @@ public final class MentionsController {
}); });
} }
public void g() { public final void g() {
this.e = false; this.e = false;
j(); j();
} }
private void h() { private final void h() {
if (this.state) { if (this.state) {
return; return;
} }
View inflate = ((ViewStub) this.j.findViewById(R.id.mentions_container_stub)).inflate(); View inflate = ((ViewStub) this.j.findViewById(R.id.mentions_container_stub)).inflate();
ViewGroup viewGroup = inflate.findViewById(R.id.mentions_container); ViewGroup viewGroup = (ViewGroup) inflate.findViewById(R.id.mentions_container);
viewGroup.addView(this.mDialogMentionComponent.a(viewGroup, null)); viewGroup.addView(this.mDialogMentionComponent.a(viewGroup, (Bundle) null));
this.mCoordinatorLayout = inflate.findViewById(R.id.mentions_cl); this.mCoordinatorLayout = inflate.findViewById(R.id.mentions_cl);;
this.mBottomSheetBehavior = (VkBottomSheetBehavior<RecyclerView>) ((CoordinatorLayout.LayoutParams) viewGroup.getLayoutParams()).getBehavior(); this.mBottomSheetBehavior = (VkBottomSheetBehavior<RecyclerView>) ((CoordinatorLayout.LayoutParams) viewGroup.getLayoutParams()).getBehavior();
this.mBottomSheetBehavior.a(new VkBottomSheetBehavior.b() { this.mBottomSheetBehavior.a(new VkBottomSheetBehavior.b() {
@Override @Override
@@ -113,12 +121,12 @@ public final class MentionsController {
this.state = true; this.state = true;
} }
public void i() { public final void i() {
this.e = true; this.e = true;
j(); j();
} }
public void j() { public final void j() {
if (this.k.d()) { if (this.k.d()) {
Context context = this.j.getContext(); Context context = this.j.getContext();
Activity f = ContextExtKt.f(context); Activity f = ContextExtKt.f(context);
@@ -132,33 +140,27 @@ public final class MentionsController {
} }
} }
public void a() { public final void a() {
this.mDialogMentionComponent.g(); this.mDialogMentionComponent.g();
} }
public void b() { public final void b() {
this.mDialogMentionComponent.h(); this.mDialogMentionComponent.h();
} }
public b c() { public final b c() {
return this.k; return this.k;
} }
public int d() { public final int d() {
return this.i; return this.i;
} }
public void e() { public final void e() {
this.mDialogMentionComponent.q(); this.mDialogMentionComponent.q();
} }
public void f() { public final void f() {
this.mDialogMentionComponent.r(); this.mDialogMentionComponent.r();
} }
public interface b {
boolean c();
boolean d();
}
} }
@@ -2,13 +2,13 @@ package com.vk.im.ui.views;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
public class Corners { public class Corners{
private int topLeft; private int topLeft;
private int topRight; private int topRight;
private int bottomLeft; private int bottomLeft;
private int bottomRight; private int bottomRight;
public Corners(int i, int i2, int i3, int i4) { public Corners(int i, int i2, int i3, int i4){
this.topLeft = i; this.topLeft = i;
this.topRight = i2; this.topRight = i2;
this.bottomLeft = i3; this.bottomLeft = i3;
@@ -23,7 +23,7 @@ public class Corners {
this(0, 0, 0, 0, 15); this(0, 0, 0, 0, 15);
} }
public static Corners a(Corners corners, int i, int i2, int i3, int i4, int i5, Object obj) { public static Corners a(Corners corners, int i, int i2, int i3, int i4, int i5, Object obj){
if ((i5 & 1) != 0) { if ((i5 & 1) != 0) {
i = corners.topLeft; i = corners.topLeft;
} }
@@ -40,30 +40,30 @@ public class Corners {
return corners; return corners;
} }
public int a() { public int a(){
return this.bottomLeft; return this.bottomLeft;
} }
public int b() { public int b(){
return this.bottomRight; return this.bottomRight;
} }
public int c() { public int c(){
return this.topLeft; return this.topLeft;
} }
public int d() { public int d(){
return this.topRight; return this.topRight;
} }
public boolean e() { public boolean e(){
int i; int i;
int i2 = this.topLeft; int i2 = this.topLeft;
int i3 = this.topRight; int i3 = this.topRight;
return i2 == i3 && i3 == (i = this.bottomRight) && this.bottomLeft == i; return i2 == i3 && i3 == (i = this.bottomRight) && this.bottomLeft == i;
} }
public boolean equals(Object obj) { public boolean equals(Object obj){
if (this != obj) { if (this != obj) {
if (!(obj instanceof Corners)) { if (!(obj instanceof Corners)) {
return false; return false;
@@ -74,24 +74,24 @@ public class Corners {
return true; return true;
} }
public boolean f() { public boolean f(){
return this.topLeft == 0 && e(); return this.topLeft == 0 && e();
} }
public void g() { public void g(){
a(0, 0); a(0, 0);
} }
public int hashCode() { public int hashCode(){
return (((((this.topLeft * 31) + this.topRight) * 31) + this.bottomLeft) * 31) + this.bottomRight; return (((((this.topLeft * 31) + this.topRight) * 31) + this.bottomLeft) * 31) + this.bottomRight;
} }
@NonNull @NonNull
public String toString() { public String toString(){
return "Corners(topLeft=" + this.topLeft + ", topRight=" + this.topRight + ", bottomLeft=" + this.bottomLeft + ", bottomRight=" + this.bottomRight + ")"; return "Corners(topLeft=" + this.topLeft + ", topRight=" + this.topRight + ", bottomLeft=" + this.bottomLeft + ", bottomRight=" + this.bottomRight + ")";
} }
public Corners a(int i, int i2) { public Corners a(int i, int i2){
if ((i2 & 1) > 0) { if ((i2 & 1) > 0) {
this.topLeft = i; this.topLeft = i;
} }
@@ -113,7 +113,7 @@ public class Corners {
return this; return this;
} }
public Corners a(int i, int i2, int i3, int i4) { public Corners a(int i, int i2, int i3, int i4){
this.topLeft = i; this.topLeft = i;
this.topRight = i2; this.topRight = i2;
this.bottomLeft = i3; this.bottomLeft = i3;
@@ -121,7 +121,7 @@ public class Corners {
return this; return this;
} }
public Corners a(Corners corners) { public Corners a(Corners corners){
this.topLeft = corners.topLeft; this.topLeft = corners.topLeft;
this.topRight = corners.topRight; this.topRight = corners.topRight;
this.bottomLeft = corners.bottomLeft; this.bottomLeft = corners.bottomLeft;
@@ -9,18 +9,19 @@ import android.graphics.Shader;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.vk.im.ui.o; import com.vk.im.ui.o;
public class StoryBorderView extends View { public class StoryBorderView extends View {
private final Paint a;
private final int g;
private final int h;
private boolean B; private boolean B;
private final Paint a;
private LinearGradient f15747b; private LinearGradient f15747b;
private int f15748c; private int f15748c;
private int f15749d; private int f15749d;
private int f15750e; private int f15750e;
private int f15751f; private int f15751f;
private final int g;
private final int h;
public StoryBorderView(Context context) { public StoryBorderView(Context context) {
this(context, null, 0, 6); this(context, null, 0, 6);
@@ -34,32 +35,10 @@ public class StoryBorderView extends View {
this(context, (i2 & 2) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i); this(context, (i2 & 2) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i);
} }
public StoryBorderView(Context context, AttributeSet attributeSet, int i) {
super(context, attributeSet, i);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
this.a = paint;
TypedArray obtainStyledAttributes = context.obtainStyledAttributes(attributeSet, o.StoryBorderView);
setBorderColor(obtainStyledAttributes.getInt(o.StoryBorderView_vkim_borderColor, 0));
this.g = obtainStyledAttributes.getInt(o.StoryBorderView_vkim_borderGradientStartColor, 0);
this.h = obtainStyledAttributes.getInt(o.StoryBorderView_vkim_borderGradientEndColor, 0);
setBorderWidth(obtainStyledAttributes.getDimensionPixelSize(o.StoryBorderView_vkim_borderWidth, 0));
obtainStyledAttributes.recycle();
}
public int getBorderColor() { public int getBorderColor() {
return this.f15749d; return this.f15749d;
} }
public void setBorderColor(int i) {
if (this.f15749d != i) {
this.f15749d = i;
this.a.setColor(i);
invalidate();
}
}
public int getBorderGradientEndColor() { public int getBorderGradientEndColor() {
return this.h; return this.h;
} }
@@ -72,33 +51,14 @@ public class StoryBorderView extends View {
return this.f15750e; return this.f15750e;
} }
public void setBorderWidth(int i) {
if (this.f15750e != i) {
this.f15750e = i;
this.a.setStrokeWidth(i);
invalidate();
}
}
public int getPadding() { public int getPadding() {
return this.f15751f; return this.f15751f;
} }
public void setPadding(int i) {
if (this.f15751f != i) {
this.f15751f = i;
setPadding(i, i, i, i);
}
}
public int getViewSize() { public int getViewSize() {
return this.f15748c; return this.f15748c;
} }
public void setViewSize(int i) {
this.f15748c = i;
}
@Override @Override
protected void onDraw(Canvas canvas) { protected void onDraw(Canvas canvas) {
canvas.drawOval(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom(), this.a); canvas.drawOval(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom(), this.a);
@@ -110,6 +70,22 @@ public class StoryBorderView extends View {
setMeasuredDimension(i3, i3); setMeasuredDimension(i3, i3);
} }
public void setBorderColor(int i) {
if (this.f15749d != i) {
this.f15749d = i;
this.a.setColor(i);
invalidate();
}
}
public void setBorderWidth(int i) {
if (this.f15750e != i) {
this.f15750e = i;
this.a.setStrokeWidth(i);
invalidate();
}
}
@Override @Override
public void setLayoutParams(ViewGroup.LayoutParams layoutParams) { public void setLayoutParams(ViewGroup.LayoutParams layoutParams) {
super.setLayoutParams(layoutParams); super.setLayoutParams(layoutParams);
@@ -133,4 +109,29 @@ public class StoryBorderView extends View {
invalidate(); invalidate();
} }
} }
public void setPadding(int i) {
if (this.f15751f != i) {
this.f15751f = i;
setPadding(i, i, i, i);
}
}
public void setViewSize(int i) {
this.f15748c = i;
}
public StoryBorderView(Context context, AttributeSet attributeSet, int i) {
super(context, attributeSet, i);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
this.a = paint;
TypedArray obtainStyledAttributes = context.obtainStyledAttributes(attributeSet, o.StoryBorderView);
setBorderColor(obtainStyledAttributes.getInt(o.StoryBorderView_vkim_borderColor, 0));
this.g = obtainStyledAttributes.getInt(o.StoryBorderView_vkim_borderGradientStartColor, 0);
this.h = obtainStyledAttributes.getInt(o.StoryBorderView_vkim_borderGradientEndColor, 0);
setBorderWidth(obtainStyledAttributes.getDimensionPixelSize(o.StoryBorderView_vkim_borderWidth, 0));
obtainStyledAttributes.recycle();
}
} }
@@ -1,5 +1,8 @@
package com.vk.im.ui.views.dialogs; package com.vk.im.ui.views.dialogs;
import static com.vk.im.ui.d.vkim_administration_title;
import static ru.vtosters.lite.utils.ThemesUtils.getAccentColor;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.TypedArray; import android.content.res.TypedArray;
@@ -14,9 +17,10 @@ import android.view.ViewGroup;
import android.view.ViewPropertyAnimator; import android.view.ViewPropertyAnimator;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.AppCompatImageView;
import b.h.g.r.MathExt;
import com.vk.core.extensions.AnimationExtKt; import com.vk.core.extensions.AnimationExtKt;
import com.vk.core.util.ContextExtKt; import com.vk.core.util.ContextExtKt;
import com.vk.core.util.Screen; import com.vk.core.util.Screen;
@@ -38,10 +42,9 @@ import com.vk.im.ui.views.FixTextView;
import com.vk.im.ui.views.avatars.AvatarView; import com.vk.im.ui.views.avatars.AvatarView;
import com.vk.im.ui.views.avatars.StoryBorderView; import com.vk.im.ui.views.avatars.StoryBorderView;
import static com.vk.im.ui.d.vkim_administration_title; import b.h.g.r.MathExt;
import static ru.vtosters.hooks.other.ThemesUtils.getAccentColor;
public class DialogItemView extends ViewGroup { public class DialogItemView extends ViewGroup{
private final int B; private final int B;
private final int C; private final int C;
private final int D; private final int D;
@@ -77,15 +80,15 @@ public class DialogItemView extends ViewGroup {
private boolean g0; private boolean g0;
private boolean h0; private boolean h0;
public DialogItemView(Context context) { public DialogItemView(Context context){
this(context, null, 0, 6); this(context, null, 0, 6);
} }
public DialogItemView(Context context, AttributeSet attributeSet) { public DialogItemView(Context context, AttributeSet attributeSet){
this(context, attributeSet, 0, 4); this(context, attributeSet, 0, 4);
} }
public DialogItemView(Context context, AttributeSet attributeSet, int i) { public DialogItemView(Context context, AttributeSet attributeSet, int i){
super(context, attributeSet, i); super(context, attributeSet, i);
Resources resources = getResources(); Resources resources = getResources();
this.a = resources.getDisplayMetrics(); this.a = resources.getDisplayMetrics();
@@ -252,11 +255,11 @@ public class DialogItemView extends ViewGroup {
addView(this.f0); addView(this.f0);
} }
public DialogItemView(Context context, AttributeSet attributeSet, int i, int i2) { public DialogItemView(Context context, AttributeSet attributeSet, int i, int i2){
this(context, (i2 & 2) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i); this(context, (i2 & 2) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i);
} }
public static ViewPropertyAnimator b(View view, float f, long j, long j2, Runnable runnable, int i, Object obj) { public static ViewPropertyAnimator b(View view, float f, long j, long j2, Runnable runnable, int i, Object obj){
if ((i & 1) != 0) { if ((i & 1) != 0) {
f = 0.0f; f = 0.0f;
} }
@@ -276,7 +279,7 @@ public class DialogItemView extends ViewGroup {
return AnimationExtKt.b(view, f, j, j2, runnable); return AnimationExtKt.b(view, f, j, j2, runnable);
} }
public static void a(View view, float f, float f2, int i, Object obj) { public static void a(View view, float f, float f2, int i, Object obj){
if ((i & 1) != 0) { if ((i & 1) != 0) {
f = 1.0f; f = 1.0f;
} }
@@ -288,7 +291,7 @@ public class DialogItemView extends ViewGroup {
AnimationExtKt.a(view, f, f2); AnimationExtKt.a(view, f, f2);
} }
public static ViewPropertyAnimator a(View view, float f, long j, long j2, Runnable runnable, int i, Object obj) { public static ViewPropertyAnimator a(View view, float f, long j, long j2, Runnable runnable, int i, Object obj){
if ((i & 1) != 0) { if ((i & 1) != 0) {
f = 1.0f; f = 1.0f;
} }
@@ -308,14 +311,14 @@ public class DialogItemView extends ViewGroup {
return AnimationExtKt.a(view, f, j, j2, runnable); return AnimationExtKt.a(view, f, j, j2, runnable);
} }
static void a(DialogItemView dialogItemView, int i, int i2, int i3, int i4, Object obj) { static void a(DialogItemView dialogItemView, int i, int i2, int i3, int i4, Object obj){
if ((i4 & 4) != 0) { if ((i4 & 4) != 0) {
i3 = 0; i3 = 0;
} }
dialogItemView.a(i, i2, i3); dialogItemView.a(i, i2, i3);
} }
static ViewGroup.MarginLayoutParams a(DialogItemView dialogItemView, int i, int i2, int i3, int i4, int i5, int i6, int i7, Object obj) { static ViewGroup.MarginLayoutParams a(DialogItemView dialogItemView, int i, int i2, int i3, int i4, int i5, int i6, int i7, Object obj){
if ((i7 & 1) != 0) { if ((i7 & 1) != 0) {
i = -2; i = -2;
} }
@@ -337,19 +340,19 @@ public class DialogItemView extends ViewGroup {
return dialogItemView.a(i, i2, i3, i4, i5, i6); return dialogItemView.a(i, i2, i3, i4, i5, i6);
} }
private Drawable getDrOnlineMobile() { private Drawable getDrOnlineMobile(){
return ContextExtKt.c(getContext(), f.ic_online_mobile_vkapp_composite_16); return ContextExtKt.c(getContext(), f.ic_online_mobile_vkapp_composite_16);
} }
private Drawable getDrOnlineVkMe() { private Drawable getDrOnlineVkMe(){
return ContextExtKt.c(getContext(), f.ic_online_mobile_vkme_composite_16); return ContextExtKt.c(getContext(), f.ic_online_mobile_vkme_composite_16);
} }
private Drawable getDrOnlineWeb() { private Drawable getDrOnlineWeb(){
return ContextExtKt.c(getContext(), f.ic_online_web_composite_16); return ContextExtKt.c(getContext(), f.ic_online_web_composite_16);
} }
private int getTimeMargin() { private int getTimeMargin(){
Layout layout = this.T.getLayout(); Layout layout = this.T.getLayout();
if (layout == null) { if (layout == null) {
@@ -371,11 +374,11 @@ public class DialogItemView extends ViewGroup {
return 0; return 0;
} }
private int getTitleColorHighlight() { private int getTitleColorHighlight(){
return ContextExtKt.a(getContext(), vkim_administration_title); return ContextExtKt.a(getContext(), vkim_administration_title);
} }
private void h(int i, int i2, int i3, int i4) { private void h(int i, int i2, int i3, int i4){
int paddingLeft = getPaddingLeft(); int paddingLeft = getPaddingLeft();
int paddingTop = getPaddingTop(); int paddingTop = getPaddingTop();
int measuredWidth = getMeasuredWidth() - getPaddingRight(); int measuredWidth = getMeasuredWidth() - getPaddingRight();
@@ -409,51 +412,51 @@ public class DialogItemView extends ViewGroup {
j(measuredWidth - r, max6, measuredWidth, q + max6); j(measuredWidth - r, max6, measuredWidth, q + max6);
} }
private int i() { private int i(){
return g(this.K); return g(this.K);
} }
private int j() { private int j(){
return f(this.T) + Math.max(f(this.V), f(this.U)); return f(this.T) + Math.max(f(this.V), f(this.U));
} }
private int k() { private int k(){
return Math.max(g(this.T), g(this.V) + g(this.U)); return Math.max(g(this.T), g(this.V) + g(this.U));
} }
private int l() { private int l(){
return Math.max(Math.max(f(this.N), f(this.R)), Math.max(f(this.O), f(this.P))); return Math.max(Math.max(f(this.N), f(this.R)), Math.max(f(this.O), f(this.P)));
} }
private int m() { private int m(){
return View.MeasureSpec.makeMeasureSpec(0, 0); return View.MeasureSpec.makeMeasureSpec(0, 0);
} }
private boolean n() { private boolean n(){
return e(this.S); return e(this.S);
} }
private int o() { private int o(){
return f(this.S); return f(this.S);
} }
private int p() { private int p(){
return g(this.S); return g(this.S);
} }
private int q() { private int q(){
return MathExt.a(f(this.b0), f(this.c0), f(this.d0), f(this.e0), f(this.f0)); return MathExt.a(f(this.b0), f(this.c0), f(this.d0), f(this.e0), f(this.f0));
} }
private int r() { private int r(){
return g(this.b0) + MathExt.a(g(this.c0), g(this.d0), g(this.e0), g(this.f0)); return g(this.b0) + MathExt.a(g(this.c0), g(this.d0), g(this.e0), g(this.f0));
} }
private int s() { private int s(){
return Math.max(f(this.a0), f(this.W)); return Math.max(f(this.a0), f(this.W));
} }
private void setAttach(CharSequence charSequence) { private void setAttach(CharSequence charSequence){
int i = VISIBLE; int i = VISIBLE;
if (charSequence == null || charSequence.length() == 0) { if (charSequence == null || charSequence.length() == 0) {
@@ -464,57 +467,57 @@ public class DialogItemView extends ViewGroup {
this.U.setText(charSequence); this.U.setText(charSequence);
} }
private void setBodyLinesCount(int i) { private void setBodyLinesCount(int i){
boolean z = i == 1; boolean z = i == 1;
this.T.setSingleLine(z); this.T.setSingleLine(z);
this.T.setMaxLines(i); this.T.setMaxLines(i);
} }
private int t() { private int t(){
return g(this.a0) + g(this.W); return g(this.a0) + g(this.W);
} }
private void u() { private void u(){
ViewExtKt.b(this.b0, this.g0 | this.h0); ViewExtKt.b(this.b0, this.g0 | this.h0);
} }
public void a(Dialog dialog, ProfilesSimpleInfo profilesSimpleInfo) { public void a(Dialog dialog, ProfilesSimpleInfo profilesSimpleInfo){
this.K.a(dialog, profilesSimpleInfo); this.K.a(dialog, profilesSimpleInfo);
} }
public void b() { public void b(){
a(null, (ComposingType) null); a(null, (ComposingType) null);
} }
public void c() { public void c(){
a(getDrOnlineMobile()); a(getDrOnlineMobile());
} }
public void d() { public void d(){
a(getDrOnlineVkMe()); a(getDrOnlineVkMe());
} }
public void e() { public void e(){
a(getDrOnlineWeb()); a(getDrOnlineWeb());
} }
public void f() { public void f(){
this.S.setVisibility(GONE); this.S.setVisibility(GONE);
this.S.e(); this.S.e();
} }
public void g() { public void g(){
b(this.L, 0.0f, 0L, 0L, null, 15, null); b(this.L, 0.0f, 0L, 0L, null, 15, null);
} }
@Override // android.view.ViewGroup, android.view.View @Override // android.view.ViewGroup, android.view.View
protected void onDetachedFromWindow() { protected void onDetachedFromWindow(){
super.onDetachedFromWindow(); super.onDetachedFromWindow();
a(this.L, 0.0f, 0.0f, 3, null); a(this.L, 0.0f, 0.0f, 3, null);
} }
@Override // android.view.ViewGroup, android.view.View @Override // android.view.ViewGroup, android.view.View
protected void onLayout(boolean z, int i, int i2, int i3, int i4) { protected void onLayout(boolean z, int i, int i2, int i3, int i4){
if (this.E) { if (this.E) {
g(i, i2, i3, i4); g(i, i2, i3, i4);
} else { } else {
@@ -523,7 +526,7 @@ public class DialogItemView extends ViewGroup {
} }
@Override // android.view.View @Override // android.view.View
protected void onMeasure(int i, int i2) { protected void onMeasure(int i, int i2){
if (this.E) { if (this.E) {
c(i); c(i);
} else { } else {
@@ -531,11 +534,11 @@ public class DialogItemView extends ViewGroup {
} }
} }
public void setAvatar(Profile profile) { public void setAvatar(Profile profile){
this.K.a(profile); this.K.a(profile);
} }
public void setBombVisible(boolean z) { public void setBombVisible(boolean z){
if (z) { if (z) {
this.b0.setImageResource(f.ic_bomb_composite_24); this.b0.setImageResource(f.ic_bomb_composite_24);
} }
@@ -545,23 +548,23 @@ public class DialogItemView extends ViewGroup {
u(); u();
} }
public void setCasperIconColor(@ColorInt int i) { public void setCasperIconColor(@ColorInt int i){
ViewExtKt.a(this.Q, i); ViewExtKt.a(this.Q, i);
} }
public void setCasperIconVisible(boolean z) { public void setCasperIconVisible(boolean z){
this.Q.setVisibility(z ? VISIBLE : GONE); this.Q.setVisibility(z ? VISIBLE : GONE);
} }
public void setErrorVisible(boolean z) { public void setErrorVisible(boolean z){
this.f0.setVisibility(z ? VISIBLE : GONE); this.f0.setVisibility(z ? VISIBLE : GONE);
} }
public void setGiftVisible(boolean z) { public void setGiftVisible(boolean z){
this.V.setVisibility(z ? VISIBLE : GONE); this.V.setVisibility(z ? VISIBLE : GONE);
} }
public void setHasStories(boolean z) { public void setHasStories(boolean z){
if (this.I == z) { if (this.I == z) {
return; return;
} }
@@ -587,7 +590,7 @@ public class DialogItemView extends ViewGroup {
setClipToPadding(!z); setClipToPadding(!z);
} }
public void setMentionVisible(boolean z) { public void setMentionVisible(boolean z){
if (z) { if (z) {
this.b0.setImageResource(f.ic_mention_composite_24); this.b0.setImageResource(f.ic_mention_composite_24);
} }
@@ -597,15 +600,15 @@ public class DialogItemView extends ViewGroup {
u(); u();
} }
public void setMutedVisible(boolean z) { public void setMutedVisible(boolean z){
this.P.setVisibility(z ? VISIBLE : GONE); this.P.setVisibility(z ? VISIBLE : GONE);
} }
public void setOnStoryClickListener(View.OnClickListener onClickListener) { public void setOnStoryClickListener(View.OnClickListener onClickListener){
ViewExtKt.b(this.M, onClickListener); ViewExtKt.b(this.M, onClickListener);
} }
public void setSender(Profile profile) { public void setSender(Profile profile){
if (profile == null) { if (profile == null) {
f(); f();
return; return;
@@ -614,29 +617,29 @@ public class DialogItemView extends ViewGroup {
this.S.a(profile); this.S.a(profile);
} }
public void setSendingVisible(boolean z) { public void setSendingVisible(boolean z){
this.e0.setVisibility(z ? VISIBLE : GONE); this.e0.setVisibility(z ? VISIBLE : GONE);
} }
public void setTime(CharSequence charSequence) { public void setTime(CharSequence charSequence){
this.R.setText(charSequence); this.R.setText(charSequence);
} }
public void setUnreadOutVisible(boolean z) { public void setUnreadOutVisible(boolean z){
this.d0.setVisibility(z ? VISIBLE : GONE); this.d0.setVisibility(z ? VISIBLE : GONE);
} }
public void setVerifiedVisible(boolean z) { public void setVerifiedVisible(boolean z){
this.O.setVisibility(z ? VISIBLE : GONE); this.O.setVisibility(z ? VISIBLE : GONE);
} }
private void a(Drawable drawable) { private void a(Drawable drawable){
ViewExtKt.c(this.L, a(16), a(20)); ViewExtKt.c(this.L, a(16), a(20));
this.L.setImageDrawable(drawable); this.L.setImageDrawable(drawable);
a(this.L, 0.0f, 0L, 0L, null, 15, null); a(this.L, 0.0f, 0L, 0L, null, 15, null);
} }
private void c(int i) { private void c(int i){
int size = (View.MeasureSpec.getSize(i) - getPaddingLeft()) - getPaddingRight(); int size = (View.MeasureSpec.getSize(i) - getPaddingLeft()) - getPaddingRight();
d(b(size - this.K.getViewSize()), m()); d(b(size - this.K.getViewSize()), m());
int r = r(); int r = r();
@@ -652,7 +655,7 @@ public class DialogItemView extends ViewGroup {
setMeasuredDimension(View.MeasureSpec.getSize(i), getPaddingTop() + getPaddingBottom() + Math.max(f(this.K), l() + Math.max(Math.max(o(), j()), Math.max(s(), q())))); setMeasuredDimension(View.MeasureSpec.getSize(i), getPaddingTop() + getPaddingBottom() + Math.max(f(this.K), l() + Math.max(Math.max(o(), j()), Math.max(s(), q()))));
} }
private void d(int i) { private void d(int i){
int size = (View.MeasureSpec.getSize(i) - getPaddingLeft()) - getPaddingRight(); int size = (View.MeasureSpec.getSize(i) - getPaddingLeft()) - getPaddingRight();
d(b(size - this.K.getViewSize()), m()); d(b(size - this.K.getViewSize()), m());
int r = r(); int r = r();
@@ -669,7 +672,7 @@ public class DialogItemView extends ViewGroup {
setMeasuredDimension(View.MeasureSpec.getSize(i), getPaddingTop() + getPaddingBottom() + Math.max(f(this.K), l() + Math.max(Math.max(o(), j()), Math.max(s(), q())))); setMeasuredDimension(View.MeasureSpec.getSize(i), getPaddingTop() + getPaddingBottom() + Math.max(f(this.K), l() + Math.max(Math.max(o(), j()), Math.max(s(), q()))));
} }
private void e(int i, int i2, int i3, int i4) { private void e(int i, int i2, int i3, int i4){
if (e(this.T) && e(this.U)) { if (e(this.T) && e(this.U)) {
c(i, i2, i3, i4); c(i, i2, i3, i4);
} else if (e(this.T)) { } else if (e(this.T)) {
@@ -680,7 +683,7 @@ public class DialogItemView extends ViewGroup {
} }
} }
private void g(int i, int i2, int i3, int i4) { private void g(int i, int i2, int i3, int i4){
int paddingLeft = getPaddingLeft(); int paddingLeft = getPaddingLeft();
int paddingTop = getPaddingTop(); int paddingTop = getPaddingTop();
int measuredWidth = getMeasuredWidth() - getPaddingRight(); int measuredWidth = getMeasuredWidth() - getPaddingRight();
@@ -703,12 +706,12 @@ public class DialogItemView extends ViewGroup {
j(measuredWidth - r, i8, measuredWidth, q + i8); j(measuredWidth - r, i8, measuredWidth, q + i8);
} }
private void i(int i, int i2, int i3, int i4) { private void i(int i, int i2, int i3, int i4){
AvatarView avatarView = this.S; AvatarView avatarView = this.S;
b(avatarView, i + b(avatarView), ((i2 + ((i4 - i2) / 2)) - (this.S.getMeasuredHeight() / 2)) + d(this.S)); b(avatarView, i + b(avatarView), ((i2 + ((i4 - i2) / 2)) - (this.S.getMeasuredHeight() / 2)) + d(this.S));
} }
private void j(int i, int i2, int i3, int i4) { private void j(int i, int i2, int i3, int i4){
int i5 = i2 + ((i4 - i2) / 2); int i5 = i2 + ((i4 - i2) / 2);
AppCompatImageView appCompatImageView = this.b0; AppCompatImageView appCompatImageView = this.b0;
b(appCompatImageView, b(appCompatImageView) + i, (i5 - (this.b0.getMeasuredHeight() / 2)) + d(this.b0)); b(appCompatImageView, b(appCompatImageView) + i, (i5 - (this.b0.getMeasuredHeight() / 2)) + d(this.b0));
@@ -725,7 +728,7 @@ public class DialogItemView extends ViewGroup {
b(appCompatImageView4, i + b(appCompatImageView4), (i5 - (this.f0.getMeasuredHeight() / 2)) + d(this.f0)); b(appCompatImageView4, i + b(appCompatImageView4), (i5 - (this.f0.getMeasuredHeight() / 2)) + d(this.f0));
} }
private void k(int i, int i2, int i3, int i4) { private void k(int i, int i2, int i3, int i4){
int i5 = i2 + ((i4 - i2) / 2); int i5 = i2 + ((i4 - i2) / 2);
TextView textView = this.W; TextView textView = this.W;
b(textView, b(textView) + i, (i5 - (this.W.getMeasuredHeight() / 2)) + d(this.W)); b(textView, b(textView) + i, (i5 - (this.W.getMeasuredHeight() / 2)) + d(this.W));
@@ -738,7 +741,7 @@ public class DialogItemView extends ViewGroup {
b(appCompatImageView, i + b(appCompatImageView), (i5 - (this.a0.getMeasuredHeight() / 2)) + d(this.a0)); b(appCompatImageView, i + b(appCompatImageView), (i5 - (this.a0.getMeasuredHeight() / 2)) + d(this.a0));
} }
public void b(CharSequence charSequence, boolean z) { public void b(CharSequence charSequence, boolean z){
int i = VISIBLE; int i = VISIBLE;
if (charSequence == null || charSequence.length() == 0) { if (charSequence == null || charSequence.length() == 0) {
@@ -752,7 +755,7 @@ public class DialogItemView extends ViewGroup {
this.g.a(z ? this.B : this.h); this.g.a(z ? this.B : this.h);
} }
private void f(int i, int i2, int i3, int i4) { private void f(int i, int i2, int i3, int i4){
TextView textView = this.N; TextView textView = this.N;
b(textView, i + b(textView), d(this.N) + i2); b(textView, i + b(textView), d(this.N) + i2);
int right = this.N.getRight() + c(this.N); int right = this.N.getRight() + c(this.N);
@@ -780,7 +783,7 @@ public class DialogItemView extends ViewGroup {
} }
} }
private void l(int i, int i2, int i3, int i4) { private void l(int i, int i2, int i3, int i4){
TextView textView = this.W; TextView textView = this.W;
b(textView, i + b(textView), i2); b(textView, i + b(textView), i2);
int right = this.W.getRight() + c(this.W); int right = this.W.getRight() + c(this.W);
@@ -788,33 +791,33 @@ public class DialogItemView extends ViewGroup {
b(appCompatImageView, right + b(appCompatImageView), (((this.W.getBottom() + this.W.getTop()) / 2) - (this.a0.getMeasuredHeight() / 2)) + d(this.a0)); b(appCompatImageView, right + b(appCompatImageView), (((this.W.getBottom() + this.W.getTop()) / 2) - (this.a0.getMeasuredHeight() / 2)) + d(this.a0));
} }
private void e(int i, int i2) { private void e(int i, int i2){
b(this.a0, i, 0, i2, 0); b(this.a0, i, 0, i2, 0);
b(this.W, i, g(this.a0), i2, 0); b(this.W, i, g(this.a0), i2, 0);
} }
public void a(CharSequence charSequence, boolean z) { public void a(CharSequence charSequence, boolean z){
this.N.setText(charSequence); this.N.setText(charSequence);
this.N.setTextColor(z ? getTitleColorHighlight() : this.f15761e); this.N.setTextColor(z ? getTitleColorHighlight() : this.f15761e);
} }
private void b(int i, int i2) { private void b(int i, int i2){
b(this.O, i, 0, i2, 0); b(this.O, i, 0, i2, 0);
b(this.Q, i, 0, i2, 0); b(this.Q, i, 0, i2, 0);
b(this.P, i, 0, i2, 0); b(this.P, i, 0, i2, 0);
b(this.R, i, 0, i2, 0); b(this.R, i, 0, i2, 0);
} }
public void a() { public void a(){
a(null, 1); a(null, 1);
setAttach(null); setAttach(null);
} }
private boolean e(View view) { private boolean e(View view){
return view.getVisibility() == VISIBLE; return view.getVisibility() == VISIBLE;
} }
public void a(CharSequence charSequence, int i, CharSequence charSequence2) { public void a(CharSequence charSequence, int i, CharSequence charSequence2){
boolean z = false; boolean z = false;
if (!(charSequence == null || charSequence.length() == 0)) { if (!(charSequence == null || charSequence.length() == 0)) {
@@ -837,11 +840,11 @@ public class DialogItemView extends ViewGroup {
} }
} }
private void b(int i, int i2, int i3) { private void b(int i, int i2, int i3){
a(this.N, i, i3, i2, 0); a(this.N, i, i3, i2, 0);
} }
private void b(int i, int i2, int i3, int i4) { private void b(int i, int i2, int i3, int i4){
int g = e(this.V) ? g(this.V) + i : i; int g = e(this.V) ? g(this.V) + i : i;
TextView textView = this.U; TextView textView = this.U;
a(textView, g + b(textView), i2 + d(this.U)); a(textView, g + b(textView), i2 + d(this.U));
@@ -849,7 +852,7 @@ public class DialogItemView extends ViewGroup {
b(appCompatImageView, i + b(appCompatImageView), (this.U.getTop() + (this.U.getMeasuredHeight() / 2)) - (this.V.getMeasuredHeight() / 2)); b(appCompatImageView, i + b(appCompatImageView), (this.U.getTop() + (this.U.getMeasuredHeight() / 2)) - (this.V.getMeasuredHeight() / 2));
} }
private void a(CharSequence charSequence, int i) { private void a(CharSequence charSequence, int i){
int i2 = VISIBLE; int i2 = VISIBLE;
if (charSequence == null || charSequence.length() == 0) { if (charSequence == null || charSequence.length() == 0) {
@@ -861,13 +864,13 @@ public class DialogItemView extends ViewGroup {
setBodyLinesCount(i); setBodyLinesCount(i);
} }
private void b(View view, int i, int i2, int i3, int i4) { private void b(View view, int i, int i2, int i3, int i4){
if (view.getVisibility() != GONE) { if (view.getVisibility() != GONE) {
a(view, i, i2, i3, i4); a(view, i, i2, i3, i4);
} }
} }
public void a(CharSequence charSequence, ComposingType composingType) { public void a(CharSequence charSequence, ComposingType composingType){
Drawable drawable = composingType == ComposingType.AUDIO ? this.H : this.G; Drawable drawable = composingType == ComposingType.AUDIO ? this.H : this.G;
boolean z = false; boolean z = false;
drawable.setVisible(!(charSequence == null || charSequence.length() == 0), false); drawable.setVisible(!(charSequence == null || charSequence.length() == 0), false);
@@ -882,13 +885,13 @@ public class DialogItemView extends ViewGroup {
this.W.setText(charSequence); this.W.setText(charSequence);
} }
private void b(View view, int i, int i2) { private void b(View view, int i, int i2){
if (view.getVisibility() == VISIBLE) { if (view.getVisibility() == VISIBLE) {
a(view, i, i2); a(view, i, i2);
} }
} }
private int b(View view) { private int b(View view){
ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams(); ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
if (marginLayoutParams != null) { if (marginLayoutParams != null) {
@@ -898,11 +901,11 @@ public class DialogItemView extends ViewGroup {
return 0; return 0;
} }
private int b(int i) { private int b(int i){
return View.MeasureSpec.makeMeasureSpec(i, MeasureSpec.AT_MOST); return View.MeasureSpec.makeMeasureSpec(i, MeasureSpec.AT_MOST);
} }
private int g(View view) { private int g(View view){
if (view.getVisibility() == GONE) { if (view.getVisibility() == GONE) {
return 0; return 0;
} }
@@ -912,13 +915,13 @@ public class DialogItemView extends ViewGroup {
return marginLayoutParams != null ? measuredWidth + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin : measuredWidth; return marginLayoutParams != null ? measuredWidth + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin : measuredWidth;
} }
private void a(int i, int i2) { private void a(int i, int i2){
a(this.K, i, 0, i2, 0); a(this.K, i, 0, i2, 0);
b(this.M, i, 0, i2, 0); b(this.M, i, 0, i2, 0);
b(this.L, i, 0, i2, 0); b(this.L, i, 0, i2, 0);
} }
private int f(View view) { private int f(View view){
if (view.getVisibility() == GONE) { if (view.getVisibility() == GONE) {
return 0; return 0;
} }
@@ -931,32 +934,32 @@ public class DialogItemView extends ViewGroup {
return measuredHeight; return measuredHeight;
} }
private void a(int i, int i2, int i3, int i4) { private void a(int i, int i2, int i3, int i4){
AvatarView avatarView = this.K; AvatarView avatarView = this.K;
a(avatarView, i + b(avatarView), i2 + d(this.K)); a(avatarView, i + b(avatarView), i2 + d(this.K));
a(this.M, this.K.getLeft() - this.K.getPaddingLeft(), this.K.getTop() - this.K.getPaddingTop()); a(this.M, this.K.getLeft() - this.K.getPaddingLeft(), this.K.getTop() - this.K.getPaddingTop());
b(this.L, this.K.getRight() - this.L.getMeasuredWidth(), this.K.getBottom() - this.L.getMeasuredHeight()); b(this.L, this.K.getRight() - this.L.getMeasuredWidth(), this.K.getBottom() - this.L.getMeasuredHeight());
} }
private void c(int i, int i2) { private void c(int i, int i2){
b(this.S, i, 0, i2, 0); b(this.S, i, 0, i2, 0);
} }
private void c(int i, int i2, int i3, int i4) { private void c(int i, int i2, int i3, int i4){
d(i, i2, i3, f(this.T) + i2); d(i, i2, i3, f(this.T) + i2);
b(i, i2 + f(this.T), i3, i4); b(i, i2 + f(this.T), i3, i4);
} }
private int h() { private int h(){
return f(this.K); return f(this.K);
} }
private void d(int i, int i2, int i3, int i4) { private void d(int i, int i2, int i3, int i4){
TextView textView = this.T; TextView textView = this.T;
a(textView, i + b(textView), i2 + d(this.T)); a(textView, i + b(textView), i2 + d(this.T));
} }
private int c(View view) { private int c(View view){
ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams(); ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
if (marginLayoutParams != null) { if (marginLayoutParams != null) {
@@ -966,7 +969,7 @@ public class DialogItemView extends ViewGroup {
return 0; return 0;
} }
private void d(int i, int i2) { private void d(int i, int i2){
b(this.b0, i, 0, i2, 0); b(this.b0, i, 0, i2, 0);
b(this.c0, i, 0, i2, 0); b(this.c0, i, 0, i2, 0);
b(this.d0, i, 0, i2, 0); b(this.d0, i, 0, i2, 0);
@@ -974,13 +977,13 @@ public class DialogItemView extends ViewGroup {
b(this.f0, i, 0, i2, 0); b(this.f0, i, 0, i2, 0);
} }
private void a(int i, int i2, int i3) { private void a(int i, int i2, int i3){
b(this.T, i, i3, i2, 0); b(this.T, i, i3, i2, 0);
b(this.V, i, i3, i2, 0); b(this.V, i, i3, i2, 0);
b(this.U, i, i3 + g(this.V), i2, 0); b(this.U, i, i3 + g(this.V), i2, 0);
} }
private int d(View view) { private int d(View view){
ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams(); ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
if (marginLayoutParams != null) { if (marginLayoutParams != null) {
@@ -990,7 +993,7 @@ public class DialogItemView extends ViewGroup {
return 0; return 0;
} }
private ViewGroup.MarginLayoutParams a(int i, int i2, int i3, int i4, int i5, int i6) { private ViewGroup.MarginLayoutParams a(int i, int i2, int i3, int i4, int i5, int i6){
ViewGroup.MarginLayoutParams marginLayoutParams = new ViewGroup.MarginLayoutParams(i, i2); ViewGroup.MarginLayoutParams marginLayoutParams = new ViewGroup.MarginLayoutParams(i, i2);
marginLayoutParams.leftMargin = i3; marginLayoutParams.leftMargin = i3;
marginLayoutParams.topMargin = i4; marginLayoutParams.topMargin = i4;
@@ -999,23 +1002,23 @@ public class DialogItemView extends ViewGroup {
return marginLayoutParams; return marginLayoutParams;
} }
public int a(int i) { public int a(int i){
return (int) (i * (this.a.densityDpi / 160.0f)); return (int) (i * (this.a.densityDpi / 160.0f));
} }
public int a(float f2) { public int a(float f2){
return (int) (f2 * (this.a.densityDpi / 160.0f)); return (int) (f2 * (this.a.densityDpi / 160.0f));
} }
private void a(View view, int i, int i2, int i3, int i4) { private void a(View view, int i, int i2, int i3, int i4){
view.measure(ViewGroup.getChildMeasureSpec(i, i2 + b(view) + c(view), view.getLayoutParams().width), ViewGroup.getChildMeasureSpec(i3, i4 + d(view) + a(view), view.getLayoutParams().height)); view.measure(ViewGroup.getChildMeasureSpec(i, i2 + b(view) + c(view), view.getLayoutParams().width), ViewGroup.getChildMeasureSpec(i3, i4 + d(view) + a(view), view.getLayoutParams().height));
} }
private void a(View view, int i, int i2) { private void a(View view, int i, int i2){
view.layout(i, i2, view.getMeasuredWidth() + i, view.getMeasuredHeight() + i2); view.layout(i, i2, view.getMeasuredWidth() + i, view.getMeasuredHeight() + i2);
} }
private int a(View view) { private int a(View view){
ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams(); ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
if (marginLayoutParams != null) { if (marginLayoutParams != null) {
@@ -1,336 +0,0 @@
package com.vk.libvideo;
import android.os.Bundle;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import com.vk.bridges.StatisticsBridge1;
import com.vk.dto.common.VideoFile;
import com.vk.media.player.PlayerTypes;
import com.vk.navigation.NavigatorKeys;
import com.vk.statistic.Statistic;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.lite.utils.Metrics;
import java.util.Locale;
import java.util.Objects;
/* loaded from: classes3.dex */
public class VideoTracker {
private final VideoFile a;
/* renamed from: b reason: collision with root package name */
private Statistic f15638b;
/* renamed from: c reason: collision with root package name */
private String f15639c;
/* renamed from: d reason: collision with root package name */
private String f15640d;
/* renamed from: e reason: collision with root package name */
private final boolean f15641e;
/* renamed from: f reason: collision with root package name */
private int f15642f = -1;
private final int g;
private final int h;
private final int i;
private final int j;
private final int k;
private int l;
private PlayerType m;
private Screen n;
/* loaded from: classes3.dex */
public enum FullscreenTransition {
TAP,
SCREEN_ROTATION
}
/* loaded from: classes3.dex */
public enum PlayerType {
INLINE,
CAROUSEL,
FULLSCREEN
}
/* loaded from: classes3.dex */
public enum ResizeAction {
BUTTON,
GESTURE
}
/* loaded from: classes3.dex */
public enum RewindType {
SLIDER,
DOUBLE_TAP
}
/* loaded from: classes3.dex */
public enum Screen {
INLINE,
CAROUSEL,
PORTRAIT,
LANDSCAPE
}
public VideoTracker(VideoFile videoFile, @Nullable Statistic statistic, String str, boolean z, @Nullable String str2) {
this.a = videoFile;
this.f15638b = statistic;
int i = videoFile.d;
this.g = (int) (i * 0.25f);
this.h = (int) (i * 0.5f);
this.i = (int) (i * 0.75f);
this.j = (int) (i * 0.95f);
this.k = i - 1;
this.f15639c = str;
this.f15641e = z;
this.f15640d = str2;
}
private static boolean a(int i, int i2, int i3) {
return i3 > i && i3 <= i2;
}
public void a(String str) {
this.f15640d = str;
}
public boolean b() {
return this.f15638b != null;
}
public void c() {
this.f15642f = -1;
}
public void d() {
c("video_fullscreen_off");
}
public void e() {
c("video_fullscreen_on");
}
public void f() {
c("video_pause");
c("pause", "pause");
}
public void g() {
c("video_resume");
c("pause", "resume");
}
public void h() {
c("video_volume_off");
c("volume", "off");
}
public void i() {
c("video_volume_on");
c("volume", "on");
}
private void c(String str, String str2) {
a(b(str, str2));
}
public String a() {
return this.f15640d;
}
public void b(String str) {
if (Objects.equals(this.f15639c, str)) {
return;
}
this.f15639c = str;
}
private void c(String str) {
if (this.f15638b != null) {
StatisticsBridge1.a().a(this.f15638b, str);
}
}
public void a(@Nullable Statistic statistic) {
this.f15638b = statistic;
}
private Bundle b(String str, String str2) {
Bundle bundle = new Bundle();
bundle.putString(NotificationCompat.CATEGORY_EVENT, str);
bundle.putString("value", str2);
bundle.putInt("position", this.f15642f);
return bundle;
}
public void a(PlayerType playerType) {
if (this.m != playerType) {
this.m = playerType;
}
}
public void a(int i, int i2) {
int i3 = this.f15642f;
if (i == i3) {
return;
}
if (a(i3, i, 0)) {
a("start", i2);
c("video_start");
}
// if (this.a.d > 0) {
// if (a(this.f15642f, i, 3)) {
// a("3s", i2);
// c("video_play_3s");
// }
// if (a(this.f15642f, i, 10)) {
// a("10s", i2);
// c("video_play_10s");
// }
// if (a(this.f15642f, i, this.g)) {
// a("25", i2);
// c("video_play_25");
// }
// if (a(this.f15642f, i, this.h)) {
// a("50", i2);
// c("video_play_50");
// }
// if (a(this.f15642f, i, this.i)) {
// a("75", i2);
// c("video_play_75");
// }
// if (a(this.f15642f, i, this.j)) {
// a("95", i2);
// c("video_play_95");
// }
// if (a(this.f15642f, i, this.k)) {
// a("100", i2);
// c("video_play_100");
// }
// }
this.f15642f = i;
}
public void a(int i) {
a("continue", i);
c("video_start");
}
public void a(@NonNull Screen screen) {
if (this.n != screen) {
this.n = screen;
c("screen", screen.toString().toLowerCase());
}
}
public void a(@NonNull FullscreenTransition fullscreenTransition) {
c("full_screen_transition", fullscreenTransition.toString().toLowerCase());
}
public void a(int i, boolean z) {
if (this.l != i) {
this.l = i;
c(z ? "auto_quality" : "quality", PlayerTypes.c(i));
}
}
public void a(@Nullable String str, boolean z) {
String str2 = z ? "auto_subtitles" : "subtitles";
if (str == null) {
str = "off";
}
c(str2, str);
}
public void a(int i, int i2, @NonNull RewindType rewindType) {
Bundle b2 = b("rewind", i <= i2 ? "forward" : "backward");
b2.putString("rewind_type", rewindType.toString().toLowerCase());
b2.putInt("rewind_start", i);
b2.putInt("rewind_end", i2);
a(b2);
}
public void a(float f2) {
String format;
if (f2 == 1.0f) {
format = "normal";
} else {
int i = (int) f2;
format = f2 == ((float) i) ? String.format(Locale.US, "%s", i) : String.format(Locale.US, "%.2f", f2);
}
c("speed", format);
}
public void a(boolean z, @NonNull ResizeAction resizeAction) {
Bundle b2 = b("resize", z ? "widen" : "narrow");
b2.putString("resize_action", resizeAction.toString().toLowerCase());
a(b2);
}
public void a(String str, String str2) {
Bundle bundle = new Bundle();
bundle.putString("link_type", str);
bundle.putString("value", str2);
bundle.putString(NotificationCompat.CATEGORY_EVENT, "show_link");
a(bundle);
}
private void a(String str, int i) {
Bundle bundle = new Bundle();
bundle.putString("autoplay", this.f15641e ? "1" : "0");
bundle.putString("position", str);
if (i >= 0) {
bundle.putInt("quality", i - 2);
}
PlayerType playerType = this.m;
if (playerType != null) {
bundle.putString("player_type", playerType.toString().toLowerCase());
}
a("video_play", bundle);
}
private void a(Bundle bundle) {
a("video_event", bundle);
}
private void a(String str, Bundle bundle) {
bundle.putString("video_id", this.a.a + "_" + this.a.b);
bundle.putString(NavigatorKeys.V, this.f15639c);
bundle.putString(NavigatorKeys.Z, this.f15639c);
if (!TextUtils.isEmpty(this.f15640d)) {
bundle.putString("context", this.f15640d);
}
if (!TextUtils.isEmpty(this.a.l0)) {
bundle.putString(NavigatorKeys.l0, this.a.l0);
}
bundle.putLong("ts", System.currentTimeMillis());
StatisticsBridge1.a().a(str, bundle);
if (Preferences.getBoolValue("sendVideoMetrics", true) && str.equals("video_play")) {
try {
sendMetrics(str);
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
}
public void sendMetrics(String event) throws JSONException {
JSONObject jsonObject = new JSONObject();
jsonObject.put("e", event);
jsonObject.put("source", this.f15639c);
jsonObject.put("ref", this.f15639c);
jsonObject.put("video_id", this.a.a + "_" + this.a.b);
jsonObject.put("position", "start");
jsonObject.put("position_sec", 0);
jsonObject.put("cur_quality", "auto");
Metrics.trackEvents(jsonObject, false);
}
}
@@ -1,71 +0,0 @@
package com.vk.medianative;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.os.Build;
import android.util.Log;
import ru.vtosters.hooks.other.Preferences;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class MediaImageEncoder {
private static boolean compressBitmap(Bitmap bitmap, File file, CompressFormat format, int quality) {
try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
return bitmap.compress(format, quality, fileOutputStream);
} catch (IOException e) {
Log.e(MediaImageEncoder.class.getSimpleName(), "Bitmap compression error: " + e);
return false;
}
}
private static boolean compressBitmapJpeg(Bitmap bitmap, File file, int quality) {
return compressBitmap(bitmap, file, CompressFormat.JPEG, quality);
}
public static boolean needToCompress() {
return Preferences.getPreferences().getBoolean("compressPhotos", true);
}
private static boolean compressBitmapNative(Bitmap bitmap, File file, int quality) {
if (MediaNative.isX86() || MediaNative.isAsus() || Build.VERSION.SDK_INT < 24) {
Log.e(MediaImageEncoder.class.getSimpleName(), "JPEG turbo not supported on this device!");
return compressBitmapJpeg(bitmap, file, quality);
}
byte[] jpegData = MediaNative.compressBitmapJpeg(bitmap, quality);
if (jpegData == null) {
return compressBitmapJpeg(bitmap, file, quality);
}
try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
fileOutputStream.write(jpegData);
return true;
} catch (IOException e) {
Log.e(MediaImageEncoder.class.getSimpleName(), "JPEG compression error: " + e);
return false;
}
}
public static boolean encodePicture(Bitmap bitmap, File file, int quality) {
if (bitmap != null && !bitmap.isRecycled() && bitmap.getWidth() * bitmap.getHeight() != 0) {
return compressBitmapNative(bitmap, file, quality);
} else {
return false;
}
}
public static boolean encodeJpeg(Bitmap bitmap, File file) {
return encodePicture(bitmap, file, Preferences.compress(85));
}
public static boolean encodeJpegWithoutCompression(Bitmap bitmap, File file) {
return encodePicture(bitmap, file, 100);
}
public static boolean encodeJpeg(Bitmap bitmap, File file, int quality) {
return encodePicture(bitmap, file, Preferences.compress(85));
}
}
@@ -1,501 +0,0 @@
package com.vk.medianative;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Process;
import android.os.*;
import android.util.Log;
import androidx.annotation.Keep;
import androidx.annotation.Nullable;
import com.facebook.soloader.SoLoader;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.util.Scanner;
public final class MediaNative {
private static final String a = NativeMediaEncoder.class.getSimpleName();
private static final Object f17443d = new Object();
@SuppressLint("StaticFieldLeak")
@Keep
public static volatile Context context;
private static boolean isMediaLoaded = false;
private static boolean isMediaMasksLoaded = false;
public static int HSLToIntRGB(float f2, float f3, float f4) {
int[] iArr = new int[3];
waitForContext();
nativeHSLToRGB(f2, f3, f4, iArr);
return Color.argb(255, iArr[0], iArr[1], iArr[2]);
}
public static void HSLToRGB(float f2, float f3, float f4, int[] iArr) {
waitForContext();
nativeHSLToRGB(f2, f3, f4, iArr);
}
public static int HSVToIntRGB(float f2, float f3, float f4) {
int[] iArr = new int[3];
waitForContext();
nativeHSVToRGB(f2, f3, f4, iArr);
return Color.argb(255, iArr[0], iArr[1], iArr[2]);
}
public static void HSVToRGB(float f2, float f3, float f4, int[] iArr) {
waitForContext();
nativeHSVToRGB(f2, f3, f4, iArr);
}
public static int LabToIntRGB(float f2, float f3, float f4) {
int[] iArr = new int[3];
waitForContext();
nativeLabToRGB(f2, f3, f4, iArr);
return Color.argb(255, iArr[0], iArr[1], iArr[2]);
}
public static void LabToRGB(float f2, float f3, float f4, int[] iArr) {
waitForContext();
nativeLabToRGB(f2, f3, f4, iArr);
}
public static void RGBToHSL(int i, int i2, int i3, float[] fArr) {
waitForContext();
nativeRGBToHSL(i, i2, i3, fArr);
}
public static void RGBToHSV(int i, int i2, int i3, float[] fArr) {
waitForContext();
nativeRGBToHSV(i, i2, i3, fArr);
}
public static void RGBToLab(int i, int i2, int i3, float[] fArr) {
waitForContext();
nativeRGBToLab(i, i2, i3, fArr);
}
public static long animationPlayerCreate(String str, int i, int i2, boolean z) {
waitForContext();
return nativeAnimationPlayerCreate(str, i, i2, z);
}
public static int animationPlayerDecode(long j, Bitmap bitmap) {
waitForContext();
return nativeAnimationPlayerDecode(j, bitmap);
}
public static int animationPlayerGetSize(long j) {
waitForContext();
return nativeAnimationPlayerGetSize(j);
}
public static void animationPlayerRelease(long j) {
waitForContext();
nativeAnimationPlayerRelease(j);
}
public static boolean animationPlayerSeek(long j, int i) {
waitForContext();
return nativeAnimationPlayerSeek(j, i);
}
public static void applyCurveAndSaturationBitmap(Bitmap bitmap, int[] iArr, float f2) {
waitForContext();
nativeCurveSaturation(bitmap, iArr, f2, Runtime.getRuntime().availableProcessors());
}
public static long audioGetTotalPcmDuration() {
waitForContext();
return nativeAudioGetTotalPcmDuration();
}
public static byte[] audioGetWaveform(short[] sArr, int i) {
waitForContext();
return nativeAudioGetWaveform(sArr, i);
}
public static int audioIsOpusFile(String str) {
waitForContext();
return nativeAudioIsOpusFile(str);
}
public static void audioReadOpusFile(ByteBuffer byteBuffer, int i, int[] iArr) {
waitForContext();
nativeAudioReadOpusFile(byteBuffer, i, iArr);
}
public static int audioSeekOpusFile(float f2) {
waitForContext();
return nativeAudioSeekOpusFile(f2);
}
public static int audioStartRecord(String str) { // need to hack
waitForContext();
return nativeAudioStartRecord(str);
}
public static void audioStopRecord() { // need to hack
waitForContext();
nativeAudioStopRecord();
}
public static int audioWriteFrame(ByteBuffer byteBuffer, int i) { // need to hack
waitForContext();
return nativeAudioWriteFrame(byteBuffer, i);
}
private static void waitForContext() {
synchronized (f17443d) {
if (context == null) {
try {
f17443d.wait();
} catch (InterruptedException e2) {
Log.e(a, "Interrupted while waiting for context", e2);
}
}
}
}
public static void blurBitmap(Bitmap bitmap, int i) {
waitForContext();
nativeBlur(bitmap, i);
}
private static String c() {
return getProcMaps(String.valueOf(Process.myPid()));
}
public static void cameraProcessorCreate() {
waitForContext();
nativeProcessorCreate();
}
public static boolean cameraProcessorDo(byte[] bArr, long[] jArr) {
waitForContext();
return nativeProcessorDo(bArr, jArr);
}
public static int cameraProcessorGetVersion() {
waitForContext();
return nativeProcessorGetVersion();
}
public static boolean cameraProcessorInit(String str, int i, int i2) {
waitForContext();
return nativeProcessorInit(str, i, i2);
}
public static boolean cameraProcessorLoad(String str, boolean z) {
waitForContext();
return nativeProcessorLoad(str, z);
}
public static void cameraProcessorMouseTap(int i, float f2, float f3) {
waitForContext();
nativeProcessorMouseTap(i, f2, f3);
}
public static void cameraProcessorRelease() {
waitForContext();
nativeProcessorRelease();
}
public static void colorCorrectionBitmap(Bitmap bitmap, Bitmap bitmap2, float[] fArr) {
waitForContext();
nativeColorCorrection(bitmap, bitmap2, fArr, fArr.length, Runtime.getRuntime().availableProcessors());
}
public static byte[] compressBitmapJpeg(Bitmap bitmap, int i) {
waitForContext();
return nativeJpegTurboCompress(bitmap, i);
}
public static String createAllInOneShader() {
waitForContext();
return nativeAllInOneShader();
}
public static void createCurve(int[] iArr, int[] iArr2, int[] iArr3, int[] iArr4, int[] iArr5, float f2, float f3, float f4, float f5, float f6) {
waitForContext();
nativeCreateCurve(iArr, iArr2, iArr3, iArr4, iArr5, f2, f3, f4, f5, f6);
}
public static String createOneInAllShader() {
waitForContext();
return nativeOneInAllShader();
}
private static String d() {
return getProcMaps("self");
}
public static String dump() {
return "LD_LIBRARY_PATH:\n" + SoLoader.makeLdLibraryPath() + "\nSELF_MAPS:\n" + d() + "\nPID_MAPS:\n" + c() + "\n";
}
private static void e() {
isMediaMasksLoaded = NativeLibLoader.loadLibrary("vkmediamasks");
}
public static void enhanceBitmap(Bitmap bitmap, float f2) {
waitForContext();
nativeEnhance(bitmap, f2, Runtime.getRuntime().availableProcessors());
}
private static void loadVKMediaLibs() {
if (isMediaLoaded) {
return;
}
isMediaLoaded = NativeLibLoader.loadLibrary("vkmedia");
isMediaLoaded = NativeLibLoader.loadLibrary("vkmediaencoder");
}
public static void flipHorizontallyBitmap(Bitmap bitmap) {
waitForContext();
nativeFlipHorizontally(bitmap);
}
public static void flipVerticallyBitmap(Bitmap bitmap) {
waitForContext();
nativeFlipVertically(bitmap);
}
public static void generateHistogram(Bitmap bitmap, int[] iArr, int[] iArr2, int[] iArr3, int[] iArr4) {
waitForContext();
nativeHistogram(bitmap, iArr, iArr2, iArr3, iArr4);
}
public static void init(Context context2) {
synchronized (f17443d) {
context = context2;
SoLoader.init(context2, false);
NativeLibLoader.loadLibrary("gnustl_shared");
NativeLibLoader.loadLibrary("vkchronicle");
loadVKMediaLibs();
f17443d.notifyAll();
}
}
public static void intRGBToHSL(int i, float[] fArr) {
waitForContext();
nativeRGBToHSL(Color.red(i), Color.green(i), Color.blue(i), fArr);
}
public static void intRGBToHSV(int i, float[] fArr) {
waitForContext();
nativeRGBToHSV(Color.red(i), Color.green(i), Color.blue(i), fArr);
}
public static void intRGBToLab(int i, float[] fArr) {
waitForContext();
nativeRGBToLab(Color.red(i), Color.green(i), Color.blue(i), fArr);
}
public static boolean isAsus() {
return "asus".equalsIgnoreCase(Build.MANUFACTURER);
}
public static boolean isMediaSupported() {
if (!isMediaMasksLoaded) {
e();
}
return isMediaMasksLoaded;
}
public static boolean isX86() {
try {
String str = Build.SUPPORTED_ABIS[0];
if (str != null) {
return str.startsWith("x86");
}
return false;
} catch (Throwable unused) {
return false;
}
}
public static void lookupBitmap(Bitmap bitmap, Bitmap bitmap2) {
waitForContext();
nativeLookup(bitmap, bitmap2, Runtime.getRuntime().availableProcessors());
}
public static long mediaEncoderCreate(MediaEncoderSettings mediaEncoderSettings) {
waitForContext();
return nativeCreateEncoder(mediaEncoderSettings);
}
public static int mediaEncoderDoEncode(long j) {
waitForContext();
return nativeDoEncode(j);
}
public static void mediaEncoderDoRelease(long j) {
waitForContext();
nativeReleaseEncoder(j);
}
private static native String nativeAllInOneShader();
private static native long nativeAnimationPlayerCreate(String str, int i, int i2, boolean z);
private static native int nativeAnimationPlayerDecode(long j, Bitmap bitmap);
private static native int nativeAnimationPlayerGetSize(long j);
private static native void nativeAnimationPlayerRelease(long j);
private static native boolean nativeAnimationPlayerSeek(long j, int i);
private static native long nativeAudioGetTotalPcmDuration();
private static native byte[] nativeAudioGetWaveform(short[] sArr, int i);
private static native int nativeAudioIsOpusFile(String str);
private static native int nativeAudioOpenOpusFile(String str);
private static native void nativeAudioReadOpusFile(ByteBuffer byteBuffer, int i, int[] iArr);
private static native int nativeAudioSeekOpusFile(float f2);
private static native int nativeAudioStartRecord(String str);
private static native void nativeAudioStopRecord();
private static native int nativeAudioWriteFrame(ByteBuffer byteBuffer, int i);
private static native void nativeBlur(Bitmap bitmap, int i);
private static native void nativeColorCorrection(Bitmap bitmap, Bitmap bitmap2, float[] fArr, int i, int i2);
private static native String nativeCreateColorCorrectionShader(float[] fArr, int i, int i2);
private static native void nativeCreateCurve(int[] iArr, int[] iArr2, int[] iArr3, int[] iArr4, int[] iArr5, float f2, float f3, float f4, float f5, float f6);
private static native long nativeCreateEncoder(MediaEncoderSettings mediaEncoderSettings);
private static native void nativeCurveSaturation(Bitmap bitmap, int[] iArr, double d2, int i);
private static native int nativeDoEncode(long j);
private static native void nativeEnhance(Bitmap bitmap, double d2, int i);
private static native void nativeFlipHorizontally(Bitmap bitmap);
private static native void nativeFlipVertically(Bitmap bitmap);
private static native void nativeHSLToRGB(float f2, float f3, float f4, int[] iArr);
private static native void nativeHSVToRGB(float f2, float f3, float f4, int[] iArr);
private static native void nativeHistogram(Bitmap bitmap, int[] iArr, int[] iArr2, int[] iArr3, int[] iArr4);
private static native byte[] nativeJpegTurboCompress(Bitmap bitmap, int i);
private static native void nativeLabToRGB(float f2, float f3, float f4, int[] iArr);
private static native void nativeLookup(Bitmap bitmap, Bitmap bitmap2, int i);
private static native String nativeOneInAllShader();
private static native void nativePinBitmap(Bitmap bitmap);
private static native void nativeProcessorCreate();
private static native boolean nativeProcessorDo(byte[] bArr, long[] jArr);
private static native int nativeProcessorGetVersion();
private static native boolean nativeProcessorInit(String str, int i, int i2);
private static native boolean nativeProcessorLoad(String str, boolean z);
private static native void nativeProcessorMouseTap(int i, float f2, float f3);
private static native void nativeProcessorRelease();
private static native void nativeRGBToHSL(int i, int i2, int i3, float[] fArr);
private static native void nativeRGBToHSV(int i, int i2, int i3, float[] fArr);
private static native void nativeRGBToLab(int i, int i2, int i3, float[] fArr);
private static native void nativeReleaseEncoder(long j);
private static native void nativeResize(Bitmap bitmap, Bitmap bitmap2, int i);
public static int openOpusFile(String str) {
waitForContext();
return nativeAudioOpenOpusFile(str);
}
public static void pinBitmap(Bitmap bitmap) {
waitForContext();
nativePinBitmap(bitmap);
}
public static void resizeBitmap(Bitmap bitmap, Bitmap bitmap2) {
waitForContext();
nativeResize(bitmap, bitmap2, Runtime.getRuntime().availableProcessors());
}
private static String getProcMaps(String str) {
try (InputStream inputStream = Runtime.getRuntime().exec("cat /proc/" + str + "/maps").getInputStream()) {
return new Scanner(inputStream).useDelimiter("\\A").next();
} catch (Exception e) {
return "empty";
}
}
public static class EncoderHandler extends Handler {
private Callback a;
public EncoderHandler(Looper looper) {
super(looper);
}
@Keep
public static Object postEventFromNative(Object obj, int i, int i2, int i3) {
EncoderHandler encoderHandler;
if (obj != null && (encoderHandler = (EncoderHandler) ((WeakReference<?>) obj).get()) != null) {
if (i == 2) {
return encoderHandler.a.getLayerBitmap(i2, i3);
}
encoderHandler.sendMessage(encoderHandler.obtainMessage(i, i2, i3, null));
}
return null;
}
@Override // android.os.Handler
public void handleMessage(Message message) {
Callback callback = this.a;
if (callback == null) {
return;
}
int i = message.what;
if (i == 0) {
callback.onBytes(message.arg1);
} else if (i != 1) {
String str = MediaNative.a;
Log.e(str, "Unknown message type " + message.what);
} else {
callback.onProgress(message.arg1);
}
}
public void setCallback(Callback callback) {
this.a = callback;
}
public interface Callback {
@Nullable
Bitmap getLayerBitmap(int i, int i2);
void onBytes(int i);
void onProgress(int i);
}
}
}
@@ -1,256 +0,0 @@
package com.vk.music.stats;
import android.content.Intent;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.core.app.NotificationCompat;
import com.vk.core.extensions.StringExt;
import com.vk.music.common.MusicPlaybackLaunchContext;
import com.vk.music.logger.MusicLogger;
import com.vk.music.stats.i.MusicPlaybackParams;
import com.vk.navigation.NavigatorKeys;
import com.vtosters.lite.data.Analytics;
import kotlin.jvm.b.Functions2;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.lite.utils.Metrics;
import java.util.Objects;
import java.util.UUID;
public final class VKMusicStatsTracker implements MusicStatsTracker {
private String a;
private final Functions2<String, Analytics.l> b;
private static final a c = new a();
public VKMusicStatsTracker(Functions2<String, Analytics.l> functions2) {
this.b = functions2;
}
private String e(MusicPlaybackParams musicPlaybackParams) {
String g = musicPlaybackParams.g();
if (g == null) {
g = this.a;
}
if (g == null) {
g = "auto";
}
this.a = g;
return g;
}
@Override
public void a(boolean z) {
MusicStatsTracker.a.a(this, z);
}
@Override
public void b(MusicPlaybackParams musicPlaybackParams) {
c.a(a(musicPlaybackParams, "music_start_playback"));
if (Preferences.sendMusicMetrics()) {
try {
makeMetricsRequest(musicPlaybackParams, "music_start_playback");
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void b(boolean z) {
}
@Override
public void c(MusicPlaybackParams musicPlaybackParams) {
MusicStatsTracker.a.b(this, musicPlaybackParams);
}
@Override
public void d() {
MusicStatsTracker.a.a(this);
}
@Override
public void a(Intent intent, String str) {
MusicStatsTracker.a.a(this, intent, str);
}
@Override
public void b(String str, @NonNull String str2) {
Analytics.l invoke = this.b.invoke("music_subscription_action");
invoke.a("popup", str);
invoke.a("action", str2);
c.a(invoke);
}
@Override
public void c(boolean z) {
MusicStatsTracker.a.b(this, z);
}
@Override
public void d(MusicPlaybackParams musicPlaybackParams) {
if (Objects.equals("pause", this.a)) {
a(musicPlaybackParams);
}
}
@Override
public void a(long j) {
MusicStatsTracker.a.a(this, j);
}
@Override
public void c() {
Analytics.l invoke = this.b.invoke("music_subscription_push");
invoke.a("action", "open");
c.a(invoke);
}
@Override
public void a(String str, MusicStatsRefer musicStatsRefer) {
Analytics.l invoke = this.b.invoke("music_subscription_show");
invoke.a("popup", str);
c.a(invoke);
}
@Override
public void b() {
Analytics.l invoke = this.b.invoke("music_subscription_push");
invoke.a("action", "send");
c.a(invoke);
}
@Override
public void a(MusicPlaybackParams musicPlaybackParams) {
c.a(a(musicPlaybackParams, "music_stop_playback"));
if (Preferences.sendMusicMetrics()) {
try {
makeMetricsRequest(musicPlaybackParams, "music_stop_playback");
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void a(PlayerStateChangedParams playerStateChangedParams) {
Analytics.l invoke = this.b.invoke("audio_player");
invoke.a(NavigatorKeys.t0, playerStateChangedParams.a());
invoke.a("prev_state", playerStateChangedParams.c());
invoke.a("duration", playerStateChangedParams.b());
c.a(invoke);
}
@Override
public void b(String str) {
Analytics.l invoke = this.b.invoke("music_subscription_free_displayed");
invoke.a("popup", str);
c.a(invoke);
}
@Override
public void a(String str) {
Analytics.l invoke = this.b.invoke("playlist_start");
invoke.a(NavigatorKeys.e, str);
c.a(invoke);
}
private void makeMetricsRequest(MusicPlaybackParams musicPlaybackParams, String str) throws JSONException {
JSONObject event = new JSONObject();
if (str.equals("music_stop_playback")) {
event.put("e", str);
event.put("audio_id", musicPlaybackParams.c());
event.put("duration", musicPlaybackParams.a());
event.put("start_time", musicPlaybackParams.i());
event.put("shuffle", "false");
event.put("reason", "new");
event.put("state", "app");
event.put("duration", musicPlaybackParams.a());
} else {
event.put("e", str);
event.put("audio_id", musicPlaybackParams.c());
event.put("start_time", musicPlaybackParams.i());
event.put("shuffle", "false");
event.put("reason", "auto");
event.put("state", "app");
if (StringExt.a((CharSequence) musicPlaybackParams.e())) {
event.put("prev_audio_id", musicPlaybackParams.e());
}
}
Metrics.trackEvents(event, true);
}
private Analytics.l a(MusicPlaybackParams musicPlaybackParams, String str) {
Analytics.l invoke = this.b.invoke(str);
invoke.a("audio_id", musicPlaybackParams.c());
invoke.a("uuid", UUID.randomUUID().hashCode());
invoke.a("shuffle", musicPlaybackParams.l());
invoke.a("reason", e(musicPlaybackParams));
invoke.a("start_time", musicPlaybackParams.i());
invoke.a("playback_started_at", musicPlaybackParams.d());
invoke.a(NavigatorKeys.l0, musicPlaybackParams.j());
if (!Objects.equals("music_start_playback", str)) {
invoke.a("duration", musicPlaybackParams.a());
}
int i = h.$EnumSwitchMapping$0[musicPlaybackParams.b().ordinal()];
if (i == 1) {
invoke.a("repeat", "one");
} else if (i == 2) {
invoke.a("repeat", "all");
}
invoke.a(NavigatorKeys.t0, musicPlaybackParams.m());
MusicPlaybackLaunchContext h = musicPlaybackParams.h();
invoke.a(NavigatorKeys.V, h.v0());
if (h.v1()) {
invoke.a("playlist_id", h.u1());
}
if (h.i(4) || h.i(8)) {
invoke.a("expanded", h.i(4));
}
if (StringExt.a((CharSequence) musicPlaybackParams.e())) {
invoke.a("prev_audio_id", musicPlaybackParams.e());
}
if (StringExt.a((CharSequence) musicPlaybackParams.f())) {
invoke.a("prev_playlist_id", musicPlaybackParams.f());
}
return invoke;
}
@Override
public void a(String str, String str2) {
boolean a2 = Objects.equals("success", str2);
Analytics.l builder = this.b.invoke("music_subscription_purchase_result");
builder.a("popup", str);
builder.a(NotificationCompat.CATEGORY_STATUS, a2 ? "success" : "fail");
if (!a2) {
builder.a("reason", str2);
}
c.a(builder);
}
@Override
public void a() {
Analytics.l invoke = this.b.invoke("music_subscription");
invoke.a("popup", "background_v2");
invoke.a("action", "link");
c.a(invoke);
}
public static final class a {
private a() {
}
@VisibleForTesting
public void a(Analytics.l lVar) {
MusicLogger.a("MusicStats", "[VK_TRACKER]", lVar);
lVar.b();
}
}
}
@@ -11,6 +11,7 @@ import com.vk.api.sdk.exceptions.VKApiExecutionException;
import com.vk.common.k.PodcastTimeCodeClickListener; import com.vk.common.k.PodcastTimeCodeClickListener;
import com.vk.common.links.LinkParser; import com.vk.common.links.LinkParser;
import com.vk.core.util.ContextExtKt; import com.vk.core.util.ContextExtKt;
import com.vk.dto.music.Artist;
import com.vk.dto.music.MusicTrack; import com.vk.dto.music.MusicTrack;
import com.vk.music.artists.chooser.MusicArtistSelector; import com.vk.music.artists.chooser.MusicArtistSelector;
import com.vk.music.common.MusicPlaybackLaunchContext; import com.vk.music.common.MusicPlaybackLaunchContext;
@@ -23,8 +24,6 @@ import com.vtosters.lite.R;
import com.vtosters.lite.ViewUtils; import com.vtosters.lite.ViewUtils;
import com.vtosters.lite.ui.MusicErrorViewHelper; import com.vtosters.lite.ui.MusicErrorViewHelper;
import com.vtosters.lite.ui.holder.RecyclerHolder; import com.vtosters.lite.ui.holder.RecyclerHolder;
import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.lite.music.Genius;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@@ -156,14 +155,6 @@ public class LyricsHolder extends RecyclerHolder<PlayerInfo> implements View.OnC
@Override // com.vk.api.base.ApiCallback @Override // com.vk.api.base.ApiCallback
public void a(VKApiExecutionException vKApiExecutionException) { public void a(VKApiExecutionException vKApiExecutionException) {
if (Preferences.getBoolValue("useGenius", false) && !Preferences.serverFeaturesDisable()) {
var text = Genius.getTextMusic(a);
var lyrics = new AudioGetLyrics.a();
lyrics.a = text;
a(lyrics);
return;
}
LyricsHolder.this.B.set(false); LyricsHolder.this.B.set(false);
LyricsHolder.this.f18328f.a(vKApiExecutionException); LyricsHolder.this.f18328f.a(vKApiExecutionException);
LyricsHolder.this.f18328f.b(0); LyricsHolder.this.f18328f.b(0);
@@ -1,106 +0,0 @@
package com.vk.newsfeed.holders;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vk.core.ui.themes.VKThemeHelper;
import com.vk.dto.newsfeed.entries.NewsEntry;
import com.vk.dto.newsfeed.entries.Post;
import com.vk.dto.newsfeed.entries.PromoPost;
import com.vk.extensions.ViewExtKt;
import com.vtosters.lite.R;
import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.newsfeed.NewsFeedFiltersUtils;
import ru.vtosters.sponsorpost.internal.Native;
import ru.vtosters.sponsorpost.internal.VotesPreferences;
import ru.vtosters.sponsorpost.internal.VotesService;
import ru.vtosters.sponsorpost.utils.PostsPreferences;
public final class AdMarkHolder extends BaseNewsEntryHolder<NewsEntry> {
private final TextView F;
@SuppressLint("ResourceType")
public AdMarkHolder(ViewGroup viewGroup) {
super(R.layout.marked_as_ads, viewGroup);
View view = ((RecyclerView.ViewHolder) this).itemView;
this.F = ViewExtKt.a(view, R.id.text, (View.OnClickListener) null);
}
@SuppressLint("ResourceType")
public void b(NewsEntry newsEntry) { // onBind
String disclamer = null;
Drawable drawable = null;
int height = 0;
if (newsEntry instanceof Post) {
Post post = ((Post) newsEntry);
if (post.L1()) {
drawable = VKThemeHelper.a(R.drawable.marked_as_ads, R.attr.icon_tertiary);
int ownerId = post.b();
int postId = post.P1();
int date = post.K();
String text = post.getText();
if (PostsPreferences.isPostAd(ownerId, postId)) {
disclamer = "SponsorPost: Реклама";
if (Preferences.isValidSignature() && Native.canVote()) {
this.F.setOnClickListener(listener -> voteDialog(ownerId, postId, date, this.F.getContext()));
}
} else if (VotesPreferences.isPostAd(ownerId, postId)) {
disclamer = "SponsorPost: Возможно реклама";
if (Preferences.isValidSignature() && Native.canVote()) {
this.F.setOnClickListener(listener -> voteDialog(ownerId, postId, date, this.F.getContext()));
}
} else if (NewsFeedFiltersUtils.sponsorFilters(text)) {
disclamer = "SponsorPost: Заблокировано фильтрами";
this.F.setOnClickListener(listener -> AndroidUtils.sendToast("Заблокировано по выражению: " + NewsFeedFiltersUtils.sponsorFiltersBanWord(text)));
} else {
disclamer = m(R.string.sponsored_post_in_group);
}
height = e0().getDimensionPixelSize(R.dimen.newsfeed_ad_mark_post_height);
}
} else if (newsEntry instanceof PromoPost) {
PromoPost promoPost = (PromoPost) newsEntry;
if (!promoPost.E1().isEmpty()) {
height = e0().getDimensionPixelSize(R.dimen.newsfeed_ad_mark_promo_post_height);
disclamer = promoPost.E1();
}
}
this.F.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null);
this.F.setMinHeight(height);
this.F.setText(disclamer);
}
public static void voteDialog(int ownerId, int postId, int date, Context ctx) {
new VkAlertDialog.Builder(ctx)
.setTitle("SponsorPost")
.setMessage("Этот пост является рекламным?")
.setPositiveButton("Да", ((dialog, which) -> {
int resp = VotesService.ratePost(ownerId, postId, date, true).optInt("code");
if (resp == 201 || resp == 100) {
AndroidUtils.sendToast("Спасибо за голос!");
} else {
AndroidUtils.sendToast("Ваш голос уже учтен");
}
}))
.setNeutralButton("Нет", ((dialog, which) -> {
int resp = VotesService.ratePost(ownerId, postId, date, false).optInt("code");
if (resp == 201 || resp == 100) {
AndroidUtils.sendToast("Спасибо за голос!");
} else {
AndroidUtils.sendToast("Ваш голос уже учтен");
}
}))
.show();
}
}
@@ -6,6 +6,7 @@ import android.graphics.Canvas;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffColorFilter;
import android.util.AttributeSet; import android.util.AttributeSet;
import com.vk.core.ui.themes.Themable; import com.vk.core.ui.themes.Themable;
import com.vk.core.ui.themes.VKThemeHelper; import com.vk.core.ui.themes.VKThemeHelper;
import com.vk.core.util.ContextExtKt; import com.vk.core.util.ContextExtKt;
@@ -13,7 +14,7 @@ import com.vk.dto.stories.model.StoriesContainer;
import com.vk.stories.view.BorderedCircleImageView; import com.vk.stories.view.BorderedCircleImageView;
import com.vtosters.lite.R; import com.vtosters.lite.R;
public final class CommunityBorderedImageView extends BorderedCircleImageView implements Themable { public final class CommunityBorderedImageView extends BorderedCircleImageView implements Themable{
private boolean f0; private boolean f0;
private int g0; private int g0;
private int h0; private int h0;
@@ -22,64 +23,64 @@ public final class CommunityBorderedImageView extends BorderedCircleImageView im
private int unread; private int unread;
private int read; private int read;
public CommunityBorderedImageView(Context context) { public CommunityBorderedImageView(Context context){
this(context, null, 0, 6); this(context, null, 0, 6);
} }
public CommunityBorderedImageView(Context context, AttributeSet attributeSet) { public CommunityBorderedImageView(Context context, AttributeSet attributeSet){
this(context, attributeSet, 0, 4); this(context, attributeSet, 0, 4);
} }
public CommunityBorderedImageView(Context context, AttributeSet attributeSet, int i, int i2) { public CommunityBorderedImageView(Context context, AttributeSet attributeSet, int i, int i2){
this(context, (i2 & 2) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i); this(context, (i2 & 2) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i);
} }
public CommunityBorderedImageView(Context context, AttributeSet attributeSet, int i) { public CommunityBorderedImageView(Context context, AttributeSet attributeSet, int i){
super(context, attributeSet, i); super(context, attributeSet, i);
this.g0 = VKThemeHelper.d(R.attr.accent); this.g0 = VKThemeHelper.d((int) R.attr.accent);
this.h0 = ContextExtKt.a(context, R.color.gray_200); this.h0 = ContextExtKt.a(context, (int) R.color.gray_200);
this.i0 = new PorterDuffColorFilter(this.g0, PorterDuff.Mode.SRC_IN); this.i0 = new PorterDuffColorFilter(this.g0, PorterDuff.Mode.SRC_IN);
this.j0 = new PorterDuffColorFilter(this.h0, PorterDuff.Mode.SRC_IN); this.j0 = new PorterDuffColorFilter(this.h0, PorterDuff.Mode.SRC_IN);
} }
public void c(int unread, int read) { // get unread and read resid public final void c(int unread, int read){ // get unread and read resid
this.unread = unread; this.unread = unread;
this.read = read; this.read = read;
this.T = BitmapFactory.decodeResource(getResources(), this.unread); this.T = BitmapFactory.decodeResource(getResources(), this.unread);
} }
public int getPrimaryColor() { public final int getPrimaryColor(){
return this.g0; return this.g0;
} }
public void setPrimaryColor(int i) { public final void setPrimaryColor(int i){
this.g0 = i; this.g0 = i;
this.i0 = new PorterDuffColorFilter(i, PorterDuff.Mode.SRC_IN); this.i0 = new PorterDuffColorFilter(i, PorterDuff.Mode.SRC_IN);
} }
public int getWasViewedColor() { public final int getWasViewedColor(){
return this.h0; return this.h0;
} }
public void setWasViewedColor(int i) { public final void setWasViewedColor(int i){
this.h0 = i; this.h0 = i;
this.j0 = new PorterDuffColorFilter(i, PorterDuff.Mode.SRC_IN); this.j0 = new PorterDuffColorFilter(i, PorterDuff.Mode.SRC_IN);
} }
public void o() { public final void o(){
this.f0 = false; this.f0 = false;
l(); l();
} }
@Override // com.vk.stories.view.ClippedImageView, android.widget.ImageView, android.view.View @Override // com.vk.stories.view.ClippedImageView, android.widget.ImageView, android.view.View
public void onDraw(Canvas canvas) { public void onDraw(Canvas canvas){
super.onDraw(canvas); super.onDraw(canvas);
if (this.f0) { if (this.f0) {
a(canvas); a(canvas);
} }
} }
public void setStoryContainer(StoriesContainer storiesContainer) { public final void setStoryContainer(StoriesContainer storiesContainer){
if (storiesContainer.L1()) { if (storiesContainer.L1()) {
this.f0 = true; this.f0 = true;
m(); m();
@@ -100,6 +101,6 @@ public final class CommunityBorderedImageView extends BorderedCircleImageView im
} }
@Override // com.vk.core.ui.themes.Themable @Override // com.vk.core.ui.themes.Themable
public void v() { public void v(){
} }
} }
@@ -1,13 +1,26 @@
package com.vk.sharing.view; package com.vk.sharing.view;
import static b.h.z.f.roboto_medium;
import static ru.vtosters.lite.utils.ThemesUtils.getAccentColor;
import android.content.Context; import android.content.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.*; import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.util.AttributeSet; import android.util.AttributeSet;
import androidx.annotation.UiThread; import androidx.annotation.UiThread;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.facebook.drawee.drawable.ScalingUtils; import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.generic.GenericDraweeHierarchy; import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.view.DraweeHolder; import com.facebook.drawee.view.DraweeHolder;
@@ -18,26 +31,23 @@ import com.vk.imageloader.view.VKMultiImageView;
import com.vk.navigation.NavigatorKeys; import com.vk.navigation.NavigatorKeys;
import com.vtosters.lite.R; import com.vtosters.lite.R;
import com.vtosters.lite.a0; import com.vtosters.lite.a0;
import ru.vtosters.hooks.other.Preferences; import ru.vtosters.lite.utils.Preferences;
import java.util.Arrays; import java.util.Arrays;
import static b.h.z.f.roboto_medium;
import static ru.vtosters.hooks.other.ThemesUtils.getAccentColor;
@UiThread @UiThread
public class TargetImageView extends VKMultiImageView { public class TargetImageView extends VKMultiImageView {
private static final int I = Screen.a(2); private static final int I = Screen.a(2);
private final int B; private final int B;
private final int C; private final int C;
private final RectF f21629d;
private final Paint f21630e;
private final RectF g;
private final Paint h;
private Drawable D; private Drawable D;
private String[] F; private String[] F;
private int G; private int G;
private final RectF f21629d;
private final Paint f21630e;
private Canvas f21631f; private Canvas f21631f;
private final RectF g;
private final Paint h;
public TargetImageView(Context context, Drawable d) { public TargetImageView(Context context, Drawable d) {
this(context, null, 0, 6); this(context, null, 0, 6);
@@ -51,43 +61,6 @@ public class TargetImageView extends VKMultiImageView {
this(context, (i2 & 2) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i); this(context, (i2 & 2) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i);
} }
public TargetImageView(Context context, AttributeSet attributeSet, int i) {
super(context, attributeSet, i);
this.f21629d = new RectF();
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setDither(true);
paint.setFilterBitmap(true);
this.f21630e = paint;
this.g = new RectF();
Paint paint2 = new Paint();
paint2.setAntiAlias(true);
paint2.setStrokeWidth(I);
paint2.setStyle(Paint.Style.STROKE);
this.h = paint2;
this.B = getAccentColor();
this.C = this.B;
Drawable c2 = ContextExtKt.c(context, R.drawable.ic_check_circle_composite_24_full);
if (c2 != null) {
this.D = c2;
this.F = new String[4];
int i2 = I * 2;
setPadding(i2, i2, i2, i2);
if (attributeSet != null) {
TypedArray obtainStyledAttributes = context.obtainStyledAttributes(attributeSet, a0.TargetImageView);
setSelected(obtainStyledAttributes.getBoolean(0, false));
obtainStyledAttributes.recycle();
}
Drawable drawable = ContextCompat.getDrawable(context, R.drawable.user_placeholder);
for (int i3 = 0; i3 <= 3; i3++) {
a();
DraweeHolder<GenericDraweeHierarchy> a3 = this.a.a(i3);
a3.b().e(drawable);
}
setScaleType(ScalingUtils.b.o);
}
}
private void e() { private void e() {
int i = this.G; int i = this.G;
for (int i2 = 0; i2 < i; i2++) { for (int i2 = 0; i2 < i; i2++) {
@@ -288,4 +261,41 @@ public class TargetImageView extends VKMultiImageView {
drawable.setBounds(i - drawable.getIntrinsicWidth(), i2 - this.D.getIntrinsicHeight(), i, i2); drawable.setBounds(i - drawable.getIntrinsicWidth(), i2 - this.D.getIntrinsicHeight(), i, i2);
f(); f();
} }
public TargetImageView(Context context, AttributeSet attributeSet, int i) {
super(context, attributeSet, i);
this.f21629d = new RectF();
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setDither(true);
paint.setFilterBitmap(true);
this.f21630e = paint;
this.g = new RectF();
Paint paint2 = new Paint();
paint2.setAntiAlias(true);
paint2.setStrokeWidth(I);
paint2.setStyle(Paint.Style.STROKE);
this.h = paint2;
this.B = getAccentColor();
this.C = this.B;
Drawable c2 = ContextExtKt.c(context, R.drawable.ic_check_circle_composite_24_full);
if (c2 != null) {
this.D = c2;
this.F = new String[4];
int i2 = I * 2;
setPadding(i2, i2, i2, i2);
if (attributeSet != null) {
TypedArray obtainStyledAttributes = context.obtainStyledAttributes(attributeSet, a0.TargetImageView);
setSelected(obtainStyledAttributes.getBoolean(0, false));
obtainStyledAttributes.recycle();
}
Drawable drawable = ContextCompat.getDrawable(context, R.drawable.user_placeholder);
for (int i3 = 0; i3 <= 3; i3++) {
a();
DraweeHolder<GenericDraweeHierarchy> a3 = this.a.a(i3);
a3.b().e(drawable);
}
setScaleType(ScalingUtils.b.o);
}
}
} }
@@ -104,25 +104,6 @@ public final class StickerDetailsAdapter extends RecyclerView.Adapter<RecyclerVi
} }
} }
private static final class d extends RecyclerView.ViewHolder {
private final VKStickerImageView mImage;
public d(ViewGroup viewGroup) {
super(new VKStickerImageView(viewGroup.getContext()));
this.mImage = (VKStickerImageView) itemView;
this.mImage.setAspectRatio(1.0f);
this.mImage.setClickable(true);
this.mImage.getHierarchy().a().setVisible(true, true);
this.mImage.getHierarchy().a(0);
this.mImage.setContentDescription(this.mImage.getContext().getString(R.string.stickers_accessibility_sticker));
}
public void a(StickerItem stickerItem) {
this.mImage.a(stickerItem.h(Screen.a(80)));
this.mImage.setTag(R.id.id, stickerItem.getId());
}
}
private final class c extends RecyclerView.ViewHolder { private final class c extends RecyclerView.ViewHolder {
private final VKImageView mImageBg; private final VKImageView mImageBg;
private final VKImageView mPackImage; private final VKImageView mPackImage;
@@ -168,4 +149,23 @@ public final class StickerDetailsAdapter extends RecyclerView.Adapter<RecyclerVi
this.mDescription.setText(stickerStockItem.C1()); this.mDescription.setText(stickerStockItem.C1());
} }
} }
private static final class d extends RecyclerView.ViewHolder {
private final VKStickerImageView mImage;
public d(ViewGroup viewGroup) {
super(new VKStickerImageView(viewGroup.getContext()));
this.mImage = (VKStickerImageView) itemView;
this.mImage.setAspectRatio(1.0f);
this.mImage.setClickable(true);
this.mImage.getHierarchy().a().setVisible(true, true);
this.mImage.getHierarchy().a(0);
this.mImage.setContentDescription(this.mImage.getContext().getString(R.string.stickers_accessibility_sticker));
}
public void a(StickerItem stickerItem) {
this.mImage.a(stickerItem.h(Screen.a(80)));
this.mImage.setTag(R.id.id, stickerItem.getId());
}
}
} }
@@ -11,9 +11,11 @@ import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.airbnb.lottie.LottieComposition; import com.airbnb.lottie.LottieComposition;
import com.airbnb.lottie.LottieCompositionFactory; import com.airbnb.lottie.LottieCompositionFactory;
import com.airbnb.lottie.LottieDrawable; import com.airbnb.lottie.LottieDrawable;
@@ -45,7 +47,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
public class StoryCircleImageView extends BorderedCircleImageView implements Themable { public class StoryCircleImageView extends BorderedCircleImageView implements Themable{
private static final HashSet<Integer> B0 = new HashSet<>(); private static final HashSet<Integer> B0 = new HashSet<>();
private final PipelineDraweeControllerBuilder f0; private final PipelineDraweeControllerBuilder f0;
private int A0; private int A0;
@@ -70,35 +72,35 @@ public class StoryCircleImageView extends BorderedCircleImageView implements The
private String y0; private String y0;
private LottieDrawable z0; private LottieDrawable z0;
public StoryCircleImageView(Context context) { public StoryCircleImageView(Context context){
this(context, null); this(context, null);
} }
public StoryCircleImageView(Context context, AttributeSet attributeSet) { public StoryCircleImageView(Context context, AttributeSet attributeSet){
this(context, attributeSet, 0); this(context, attributeSet, 0);
} }
public StoryCircleImageView(Context context, AttributeSet attributeSet, int i) { public StoryCircleImageView(Context context, AttributeSet attributeSet, int i){
super(context, attributeSet, i); super(context, attributeSet, i);
this.f0 = FrescoWrapper.c.d(); this.f0 = FrescoWrapper.c.d();
a(context, attributeSet, i); a(context, attributeSet, i);
} }
private void b(Canvas canvas) { private void b(Canvas canvas){
this.z0.draw(canvas); this.z0.draw(canvas);
} }
private boolean o() { private boolean o(){
return !this.u0 && !this.t0 && this.z0 == null && !this.w0 && !this.v0; return !this.u0 && !this.t0 && this.z0 == null && !this.w0 && !this.v0;
} }
private void p() { private void p(){
this.z0.stop(); this.z0.stop();
this.z0 = null; this.z0 = null;
invalidate(); invalidate();
} }
private void q() { private void q(){
int i = this.j0; int i = this.j0;
if (i != 0 && VKThemeHelper.k.a(i)) { if (i != 0 && VKThemeHelper.k.a(i)) {
this.k0 = VKThemeHelper.d(this.j0); this.k0 = VKThemeHelper.d(this.j0);
@@ -130,19 +132,19 @@ public class StoryCircleImageView extends BorderedCircleImageView implements The
this.s0 = DrawableUtils.a(a4, i8, i8); this.s0 = DrawableUtils.a(a4, i8, i8);
} }
private void r() { private void r(){
this.c0 = Screen.a(o() ? 0 : 2); this.c0 = Screen.a(o() ? 0 : 2);
m(); m();
q(); q();
} }
private void setUploadFailed(boolean z) { private void setUploadFailed(boolean z){
this.u0 = z; this.u0 = z;
invalidate(); invalidate();
} }
@Override // com.vk.stories.view.ClippedImageView, android.widget.ImageView, android.view.View @Override // com.vk.stories.view.ClippedImageView, android.widget.ImageView, android.view.View
public void onDraw(Canvas canvas) { public void onDraw(Canvas canvas){
super.onDraw(canvas); super.onDraw(canvas);
setBorderAlpha(255); setBorderAlpha(255);
if (this.u0) { if (this.u0) {
@@ -168,13 +170,13 @@ public class StoryCircleImageView extends BorderedCircleImageView implements The
} }
@Override // com.vk.stories.view.BorderedCircleImageView, android.view.View @Override // com.vk.stories.view.BorderedCircleImageView, android.view.View
public void onSizeChanged(int i, int i2, int i3, int i4) { public void onSizeChanged(int i, int i2, int i3, int i4){
super.onSizeChanged(i, i2, i3, i4); super.onSizeChanged(i, i2, i3, i4);
this.i0.setBounds(0, 0, i, i2); this.i0.setBounds(0, 0, i, i2);
b(i); b(i);
} }
public void setStoryContainer(@Nullable StoriesContainer storiesContainer) { public void setStoryContainer(@Nullable StoriesContainer storiesContainer){
boolean z = true; boolean z = true;
boolean z2 = storiesContainer != null && storiesContainer.Q1(); boolean z2 = storiesContainer != null && storiesContainer.Q1();
this.v0 = storiesContainer != null && storiesContainer.S1() && !storiesContainer.L1(); this.v0 = storiesContainer != null && storiesContainer.S1() && !storiesContainer.L1();
@@ -244,12 +246,12 @@ public class StoryCircleImageView extends BorderedCircleImageView implements The
} }
@Override // com.vk.core.ui.themes.Themable @Override // com.vk.core.ui.themes.Themable
public void v() { public void v(){
r(); r();
invalidate(); invalidate();
} }
private void b(int i) { private void b(int i){
LottieDrawable lottieDrawable = this.z0; LottieDrawable lottieDrawable = this.z0;
if (lottieDrawable == null || lottieDrawable.e() == null) { if (lottieDrawable == null || lottieDrawable.e() == null) {
return; return;
@@ -257,7 +259,7 @@ public class StoryCircleImageView extends BorderedCircleImageView implements The
this.z0.d(i / this.z0.e().a().width()); this.z0.d(i / this.z0.e().a().width());
} }
protected void a(Context context, AttributeSet attributeSet, int i) { protected void a(Context context, AttributeSet attributeSet, int i){
TypedArray obtainStyledAttributes = context.obtainStyledAttributes(attributeSet, com.vtosters.lite.a0.StoryCircleImageView, i, 0); TypedArray obtainStyledAttributes = context.obtainStyledAttributes(attributeSet, com.vtosters.lite.a0.StoryCircleImageView, i, 0);
a(context, attributeSet, obtainStyledAttributes); a(context, attributeSet, obtainStyledAttributes);
obtainStyledAttributes.recycle(); obtainStyledAttributes.recycle();
@@ -265,7 +267,7 @@ public class StoryCircleImageView extends BorderedCircleImageView implements The
this.T = this.p0; this.T = this.p0;
} }
public void b(@Nullable List<String> list) { public void b(@Nullable List<String> list){
PipelineDraweeControllerBuilder pipelineDraweeControllerBuilder = this.f0; PipelineDraweeControllerBuilder pipelineDraweeControllerBuilder = this.f0;
pipelineDraweeControllerBuilder.j(); pipelineDraweeControllerBuilder.j();
pipelineDraweeControllerBuilder.a(getController()); pipelineDraweeControllerBuilder.a(getController());
@@ -275,7 +277,7 @@ public class StoryCircleImageView extends BorderedCircleImageView implements The
} }
@SuppressLint("ResourceType") @SuppressLint("ResourceType")
private void a(Context context, AttributeSet attributeSet, TypedArray typedArray) { // bullshit vk code is not working with custom bordered circle image private void a(Context context, AttributeSet attributeSet, TypedArray typedArray){ // bullshit vk code is not working with custom bordered circle image
Drawable drawable; Drawable drawable;
this.A0 = typedArray.getDimensionPixelSize(0, Screen.a(64.0f)); this.A0 = typedArray.getDimensionPixelSize(0, Screen.a(64.0f));
if (typedArray.hasValue(2)) { if (typedArray.hasValue(2)) {
@@ -342,13 +344,13 @@ public class StoryCircleImageView extends BorderedCircleImageView implements The
this.s0 = DrawableUtils.a(drawable4, i4, i4); this.s0 = DrawableUtils.a(drawable4, i4, i4);
} }
public void a(StoriesContainer storiesContainer) { public void a(StoriesContainer storiesContainer){
if (this.z0 == null) { if (this.z0 == null) {
LottieCompositionFactory.a(getContext(), this.y0).b(new a(storiesContainer)); LottieCompositionFactory.a(getContext(), this.y0).b(new a(storiesContainer));
} }
} }
public void a(StoriesContainer storiesContainer, LottieComposition lottieComposition) { public void a(StoriesContainer storiesContainer, LottieComposition lottieComposition){
this.z0 = new LottieDrawable(); this.z0 = new LottieDrawable();
this.z0.a(lottieComposition); this.z0.a(lottieComposition);
this.z0.d(-1); this.z0.d(-1);
@@ -361,7 +363,7 @@ public class StoryCircleImageView extends BorderedCircleImageView implements The
this.z0.stop(); this.z0.stop();
} }
private void a(boolean z, boolean z2) { private void a(boolean z, boolean z2){
k(); k();
this.t0 = z; this.t0 = z;
if (!z2) { if (!z2) {
@@ -371,7 +373,7 @@ public class StoryCircleImageView extends BorderedCircleImageView implements The
} }
} }
private void a(@NonNull PipelineDraweeControllerBuilder pipelineDraweeControllerBuilder, @Nullable final List<String> list) { private void a(@NonNull PipelineDraweeControllerBuilder pipelineDraweeControllerBuilder, @Nullable final List<String> list){
pipelineDraweeControllerBuilder.b(null); pipelineDraweeControllerBuilder.b(null);
pipelineDraweeControllerBuilder.a((Supplier<DataSource<CloseableReference<com.facebook.x.g.CloseableImage>>>) null); pipelineDraweeControllerBuilder.a((Supplier<DataSource<CloseableReference<com.facebook.x.g.CloseableImage>>>) null);
if (list != null && !list.isEmpty()) { if (list != null && !list.isEmpty()) {
@@ -382,13 +384,13 @@ public class StoryCircleImageView extends BorderedCircleImageView implements The
return; return;
} }
pipelineDraweeControllerBuilder.a(() -> StoryCircleImageView.this.a(list)); pipelineDraweeControllerBuilder.a((Supplier<DataSource<CloseableReference<CloseableImage>>>) () -> StoryCircleImageView.this.a(list));
return; return;
} }
pipelineDraweeControllerBuilder.b(null); pipelineDraweeControllerBuilder.b(null);
} }
public DataSource<CloseableReference<CloseableImage>> a(@Nullable List<String> list) { public DataSource<CloseableReference<CloseableImage>> a(@Nullable List<String> list){
ArrayList<Image> arrayList = new ArrayList<>(); ArrayList<Image> arrayList = new ArrayList<>();
for (String o : Objects.requireNonNull(list)) { for (String o : Objects.requireNonNull(list)) {
arrayList.add(new Image(-1, -1, o)); arrayList.add(new Image(-1, -1, o));
@@ -396,15 +398,15 @@ public class StoryCircleImageView extends BorderedCircleImageView implements The
return AvatarDataSource.a(arrayList, this.A0, 0); return AvatarDataSource.a(arrayList, this.A0, 0);
} }
public class a implements LottieListener<LottieComposition> { public class a implements LottieListener<LottieComposition>{
final StoriesContainer a; final StoriesContainer a;
a(StoriesContainer storiesContainer) { a(StoriesContainer storiesContainer){
this.a = storiesContainer; this.a = storiesContainer;
} }
@Override // com.airbnb.lottie.LottieListener @Override // com.airbnb.lottie.LottieListener
public void a(LottieComposition lottieComposition) { public void a(LottieComposition lottieComposition){
if (StoryCircleImageView.this.getWidth() > 0) { if (StoryCircleImageView.this.getWidth() > 0) {
StoryCircleImageView.this.a(this.a, lottieComposition); StoryCircleImageView.this.a(this.a, lottieComposition);
} else { } else {
@@ -412,15 +414,15 @@ public class StoryCircleImageView extends BorderedCircleImageView implements The
} }
} }
public class ViewTreeObserver$OnGlobalLayoutListenerC0393a implements ViewTreeObserver.OnGlobalLayoutListener { public class ViewTreeObserver$OnGlobalLayoutListenerC0393a implements ViewTreeObserver.OnGlobalLayoutListener{
final LottieComposition a; final LottieComposition a;
ViewTreeObserver$OnGlobalLayoutListenerC0393a(LottieComposition lottieComposition) { ViewTreeObserver$OnGlobalLayoutListenerC0393a(LottieComposition lottieComposition){
this.a = lottieComposition; this.a = lottieComposition;
} }
@Override // android.view.ViewTreeObserver.OnGlobalLayoutListener @Override // android.view.ViewTreeObserver.OnGlobalLayoutListener
public void onGlobalLayout() { public void onGlobalLayout(){
StoryCircleImageView.this.getViewTreeObserver().removeOnGlobalLayoutListener(this); StoryCircleImageView.this.getViewTreeObserver().removeOnGlobalLayoutListener(this);
a aVar = a.this; a aVar = a.this;
StoryCircleImageView.this.a(aVar.a, this.a); StoryCircleImageView.this.a(aVar.a, this.a);
@@ -428,12 +430,12 @@ public class StoryCircleImageView extends BorderedCircleImageView implements The
} }
} }
public class b implements ValueAnimator.AnimatorUpdateListener { public class b implements ValueAnimator.AnimatorUpdateListener{
b() { b(){
} }
@Override // android.animation.ValueAnimator.AnimatorUpdateListener @Override // android.animation.ValueAnimator.AnimatorUpdateListener
public void onAnimationUpdate(ValueAnimator valueAnimator) { public void onAnimationUpdate(ValueAnimator valueAnimator){
StoryCircleImageView.this.invalidate(); StoryCircleImageView.this.invalidate();
} }
} }
+64 -169
View File
@@ -222,10 +222,8 @@ public final class R {
public static final int undel_value = 0x7f030075; // 2130903157 public static final int undel_value = 0x7f030075; // 2130903157
public static final int wallpaper_change_dialog = 0x7f030076; // 2130903158 public static final int wallpaper_change_dialog = 0x7f030076; // 2130903158
public static final int accent_select_type = 0x7f030077; // 2130903159 public static final int accent_select_type = 0x7f030077; // 2130903159
public static final int compression = 0x7f030078; // 2130903160 public static final int theme_type_name = 0x7f030078; // 2130903160
public static final int compression_value = 0x7f030079; // 2130903161 public static final int theme_type_name_checkbox = 0x7f030079; // 2130903161
public static final int theme_type_name = 0x7f03007a; // 2130903162
public static final int theme_type_name_checkbox = 0x7f03007b; // 2130903163
} }
public static final class attr { public static final class attr {
@@ -4976,29 +4974,28 @@ public final class R {
public static final int ic_deepl_logo_icon = 0x7f080bcb; // 2131233739 public static final int ic_deepl_logo_icon = 0x7f080bcb; // 2131233739
public static final int ic_google_translate_logo = 0x7f080bcc; // 2131233740 public static final int ic_google_translate_logo = 0x7f080bcc; // 2131233740
public static final int ic_yandex_translate_icon = 0x7f080bd1; // 2131233745 public static final int ic_yandex_translate_icon = 0x7f080bd1; // 2131233745
public static final int $splash__0 = 0x7f080bd2; // 2131233746 public static final int microsoft = 0x7f080bd2; // 2131233746
public static final int roundmsg = 0x7f080bd3; // 2131233747 public static final int roundmsg = 0x7f080bd3; // 2131233747
public static final int tgs_entry_background = 0x7f080bd4; // 2131233748 public static final int tgs_entry_background = 0x7f080bd4; // 2131233748
public static final int yandex = 0x7f080bd7; // 2131233751 public static final int yandex = 0x7f080bd7; // 2131233751
public static final int $splash__1 = 0x7f080bd8; // 2131233752 public static final int $splash__0 = 0x7f080bd8; // 2131233752
public static final int $splash__10 = 0x7f080bd9; // 2131233753 public static final int $splash__1 = 0x7f080bd9; // 2131233753
public static final int $splash__11 = 0x7f080bda; // 2131233754 public static final int $splash__10 = 0x7f080bda; // 2131233754
public static final int $splash__12 = 0x7f080bdb; // 2131233755 public static final int $splash__11 = 0x7f080bdb; // 2131233755
public static final int $splash__13 = 0x7f080bdc; // 2131233756 public static final int $splash__12 = 0x7f080bdc; // 2131233756
public static final int $splash__14 = 0x7f080bdd; // 2131233757 public static final int $splash__13 = 0x7f080bdd; // 2131233757
public static final int $splash__15 = 0x7f080bde; // 2131233758 public static final int $splash__14 = 0x7f080bde; // 2131233758
public static final int $splash__2 = 0x7f080bdf; // 2131233759 public static final int $splash__15 = 0x7f080bdf; // 2131233759
public static final int $splash__3 = 0x7f080be0; // 2131233760 public static final int $splash__2 = 0x7f080be0; // 2131233760
public static final int $splash__4 = 0x7f080be1; // 2131233761 public static final int $splash__3 = 0x7f080be1; // 2131233761
public static final int $splash__5 = 0x7f080be2; // 2131233762 public static final int $splash__4 = 0x7f080be2; // 2131233762
public static final int $splash__6 = 0x7f080be3; // 2131233763 public static final int $splash__5 = 0x7f080be3; // 2131233763
public static final int $splash__7 = 0x7f080be4; // 2131233764 public static final int $splash__6 = 0x7f080be4; // 2131233764
public static final int $splash__8 = 0x7f080be5; // 2131233765 public static final int $splash__7 = 0x7f080be5; // 2131233765
public static final int $splash__9 = 0x7f080be6; // 2131233766 public static final int $splash__8 = 0x7f080be6; // 2131233766
public static final int $splash__9 = 0x7f080be7; // 2131233767
public static final int checker_background = 0x7f080be8; // 2131233768 public static final int checker_background = 0x7f080be8; // 2131233768
public static final int custom_thumb_selector = 0x7f080be9; // 2131233769 public static final int splash = 0x7f080be9; // 2131233769
public static final int custom_track_selector = 0x7f080bea; // 2131233770
public static final int splash = 0x7f080bec; // 2131233772
public static final int abc_control_background_material = 0x7f080032; // 2131230770 public static final int abc_control_background_material = 0x7f080032; // 2131230770
public static final int ic_action_close = 0x7f080322; // 2131231522 public static final int ic_action_close = 0x7f080322; // 2131231522
public static final int ic_camera_outline_28_new = 0x7f0803a0; // 2131231648 public static final int ic_camera_outline_28_new = 0x7f0803a0; // 2131231648
@@ -6796,9 +6793,6 @@ public final class R {
public static final int ic_telegram_24 = 0x7f080bcf; // 2131233743 public static final int ic_telegram_24 = 0x7f080bcf; // 2131233743
public static final int ic_telegram_outline_28 = 0x7f080bd0; // 2131233744 public static final int ic_telegram_outline_28 = 0x7f080bd0; // 2131233744
public static final int vtlogo = 0x7f080bd6; // 2131233750 public static final int vtlogo = 0x7f080bd6; // 2131233750
public static final int bing = 0x7f080be7; // 2131233767
public static final int sauceNAO = 0x7f080beb; // 2131233771
public static final int tracemoe = 0x7f080bed; // 2131233773
public static final int bg_music_play_button_white = 0x7f08015e; // 2131231070 public static final int bg_music_play_button_white = 0x7f08015e; // 2131231070
public static final int bg_poll_bg_thumb = 0x7f080181; // 2131231105 public static final int bg_poll_bg_thumb = 0x7f080181; // 2131231105
public static final int bg_stickers_suggestions_left = 0x7f0801ad; // 2131231149 public static final int bg_stickers_suggestions_left = 0x7f0801ad; // 2131231149
@@ -11060,8 +11054,6 @@ public final class R {
public static final int color_name = 0x7f0a1022; // 2131365922 public static final int color_name = 0x7f0a1022; // 2131365922
public static final int color_value = 0x7f0a1023; // 2131365923 public static final int color_value = 0x7f0a1023; // 2131365923
public static final int color_preview_border = 0x7f0a1024; // 2131365924 public static final int color_preview_border = 0x7f0a1024; // 2131365924
public static final int account_backup_view = 0x7f0a1025; // 2131365925
public static final int copy_image = 0x7f0a1026; // 2131365926
} }
public static final class integer { public static final class integer {
@@ -13001,31 +12993,7 @@ public final class R {
public static final int vt_changeable_foreground = 0x7f0f0044; // 2131689540 public static final int vt_changeable_foreground = 0x7f0f0044; // 2131689540
public static final int vt_launcher = 0x7f0f0045; // 2131689541 public static final int vt_launcher = 0x7f0f0045; // 2131689541
public static final int vt_party_foreground = 0x7f0f0047; // 2131689543 public static final int vt_party_foreground = 0x7f0f0047; // 2131689543
public static final int ic_launcher_balloon_pink = 0x7f0f0048; // 2131689544 public static final int vt_adaptive_launcher_foneground = 0x7f0f0043; // 2131689539
public static final int ic_launcher_balloon_pink_background = 0x7f0f0049; // 2131689545
public static final int ic_launcher_balloon_pink_foreground = 0x7f0f004a; // 2131689546
public static final int ic_launcher_bubble_gum = 0x7f0f004b; // 2131689547
public static final int ic_launcher_bubble_gum_background = 0x7f0f004c; // 2131689548
public static final int ic_launcher_bubble_gum_foreground = 0x7f0f004d; // 2131689549
public static final int ic_launcher_comics = 0x7f0f004e; // 2131689550
public static final int ic_launcher_comics_background = 0x7f0f004f; // 2131689551
public static final int ic_launcher_comics_foreground = 0x7f0f0050; // 2131689552
public static final int ic_launcher_flowers = 0x7f0f0051; // 2131689553
public static final int ic_launcher_flowers_background = 0x7f0f0052; // 2131689554
public static final int ic_launcher_flowers_foreground = 0x7f0f0053; // 2131689555
public static final int ic_launcher_metal_dark = 0x7f0f0054; // 2131689556
public static final int ic_launcher_metal_dark_background = 0x7f0f0055; // 2131689557
public static final int ic_launcher_metal_dark_foreground = 0x7f0f0056; // 2131689558
public static final int ic_launcher_pin_blue = 0x7f0f0057; // 2131689559
public static final int ic_launcher_pin_blue_background = 0x7f0f0058; // 2131689560
public static final int ic_launcher_pin_blue_foreground = 0x7f0f0059; // 2131689561
public static final int ic_launcher_rabbit = 0x7f0f005a; // 2131689562
public static final int ic_launcher_rabbit_background = 0x7f0f005b; // 2131689563
public static final int ic_launcher_rabbit_foreground = 0x7f0f005c; // 2131689564
public static final int ic_launcher_shine = 0x7f0f005d; // 2131689565
public static final int ic_launcher_shine_background = 0x7f0f005e; // 2131689566
public static final int ic_launcher_shine_foreground = 0x7f0f005f; // 2131689567
public static final int vt_adaptive_launcher_foreground = 0x7f0f0043; // 2131689539
public static final int vt_launcher_round = 0x7f0f0046; // 2131689542 public static final int vt_launcher_round = 0x7f0f0046; // 2131689542
public static final int ic_logo_facebook_28 = 0x7f0f0003; // 2131689475 public static final int ic_logo_facebook_28 = 0x7f0f0003; // 2131689475
public static final int ic_logo_google_28 = 0x7f0f0004; // 2131689476 public static final int ic_logo_google_28 = 0x7f0f0004; // 2131689476
@@ -19579,121 +19547,49 @@ public final class R {
public static final int accent_color_summ = 0x7f12183b; // 2131892283 public static final int accent_color_summ = 0x7f12183b; // 2131892283
public static final int accent_color_title = 0x7f12183c; // 2131892284 public static final int accent_color_title = 0x7f12183c; // 2131892284
public static final int accents = 0x7f12183d; // 2131892285 public static final int accents = 0x7f12183d; // 2131892285
public static final int accounts_saved_by_path = 0x7f12183e; // 2131892286 public static final int add_to_ads_stories_whitelist = 0x7f12183e; // 2131892286
public static final int add_to_ads_stories_whitelist = 0x7f12183f; // 2131892287 public static final int amoledtheme_summ = 0x7f12183f; // 2131892287
public static final int amoledtheme_summ = 0x7f121840; // 2131892288 public static final int amoledtheme_title = 0x7f121840; // 2131892288
public static final int amoledtheme_title = 0x7f121841; // 2131892289 public static final int app_open_by_default_settings = 0x7f121841; // 2131892289
public static final int appLanguage = 0x7f121842; // 2131892290 public static final int audio_deleted_from_cache = 0x7f121842; // 2131892290
public static final int app_open_by_default_settings = 0x7f121843; // 2131892291 public static final int blockminiapps_summ = 0x7f121843; // 2131892291
public static final int applying_accent = 0x7f121844; // 2131892292 public static final int blockminiapps_title = 0x7f121844; // 2131892292
public static final int audio_deleted_from_cache = 0x7f121845; // 2131892293 public static final int businessDisabler_title = 0x7f121845; // 2131892293
public static final int blockminiapps_summ = 0x7f121846; // 2131892294 public static final int by_choice = 0x7f121846; // 2131892294
public static final int blockminiapps_title = 0x7f121847; // 2131892295 public static final int calls_not_available = 0x7f121847; // 2131892295
public static final int businessDisabler_title = 0x7f121848; // 2131892296 public static final int cannot_write = 0x7f121848; // 2131892296
public static final int by_choice = 0x7f121849; // 2131892297 public static final int change_accent_color = 0x7f121849; // 2131892297
public static final int calls_not_available = 0x7f12184a; // 2131892298 public static final int copydebuginfo_summ = 0x7f12184a; // 2131892298
public static final int cannot_write = 0x7f12184b; // 2131892299 public static final int copydebuginfo_title = 0x7f12184b; // 2131892299
public static final int change_accent_color = 0x7f12184c; // 2131892300 public static final int copyownlink_summ = 0x7f12184c; // 2131892300
public static final int compression_types = 0x7f12184d; // 2131892301 public static final int copyownlink_title = 0x7f12184d; // 2131892301
public static final int compression_types_selection = 0x7f12184e; // 2131892302 public static final int crash_service_name = 0x7f12184e; // 2131892302
public static final int copydebuginfo_summ = 0x7f12184f; // 2131892303 public static final int current_theme = 0x7f12184f; // 2131892303
public static final int copydebuginfo_title = 0x7f121850; // 2131892304 public static final int custom_links_warning = 0x7f121850; // 2131892304
public static final int copyownlink_summ = 0x7f121851; // 2131892305 public static final int data_updated = 0x7f121851; // 2131892305
public static final int copyownlink_title = 0x7f121852; // 2131892306 public static final int device_info = 0x7f121852; // 2131892306
public static final int crash_service_name = 0x7f121853; // 2131892307 public static final int device_info_copied = 0x7f121853; // 2131892307
public static final int currentLanguage = 0x7f121854; // 2131892308 public static final int dialogstats = 0x7f121854; // 2131892308
public static final int current_theme = 0x7f121855; // 2131892309 public static final int downloading_update = 0x7f121855; // 2131892309
public static final int custom_links_warning = 0x7f121856; // 2131892310 public static final int invalid_pack_link = 0x7f121856; // 2131892310
public static final int data = 0x7f121857; // 2131892311 public static final int maxquality_summ = 0x7f121857; // 2131892311
public static final int data_updated = 0x7f121858; // 2131892312 public static final int maxquality_title = 0x7f121858; // 2131892312
public static final int datasettings_title = 0x7f121859; // 2131892313 public static final int monettheme_summ = 0x7f121859; // 2131892313
public static final int device_info = 0x7f12185a; // 2131892314 public static final int monettheme_title = 0x7f12185a; // 2131892314
public static final int device_info_copied = 0x7f12185b; // 2131892315 public static final int newsfeed_notif_summ = 0x7f12185b; // 2131892315
public static final int dialogstats = 0x7f12185c; // 2131892316 public static final int newsfeed_notif_title = 0x7f12185c; // 2131892316
public static final int disable_analytics = 0x7f12185d; // 2131892317 public static final int open_bot = 0x7f12185d; // 2131892317
public static final int disable_analytics_summ = 0x7f12185e; // 2131892318 public static final int promotedstickers_title = 0x7f12185e; // 2131892318
public static final int downloading_update = 0x7f12185f; // 2131892319 public static final int remove_from_ads_stories_whitelist = 0x7f12185f; // 2131892319
public static final int error_applying_accent = 0x7f121860; // 2131892320 public static final int select_color = 0x7f121860; // 2131892320
public static final int error_no_text = 0x7f121861; // 2131892321 public static final int select_palette = 0x7f121861; // 2131892321
public static final int error_saving_file = 0x7f121862; // 2131892322 public static final int sources = 0x7f121862; // 2131892322
public static final int failed_to_get_text = 0x7f121863; // 2131892323 public static final int updateverifdata_summ = 0x7f121863; // 2131892323
public static final int invalid_pack_link = 0x7f121864; // 2131892324 public static final int updateverifdata_title = 0x7f121864; // 2131892324
public static final int invalidate_theme_cache_title = 0x7f121865; // 2131892325 public static final int useOldAppVer_summ = 0x7f121865; // 2131892325
public static final int logColors_title = 0x7f121866; // 2131892326 public static final int useOldAppVer_title = 0x7f121866; // 2131892326
public static final int maxquality_summ = 0x7f121867; // 2131892327 public static final int vkx_integration_enabled_info = 0x7f121867; // 2131892327
public static final int maxquality_title = 0x7f121868; // 2131892328 public static final int writebar_ios_title = 0x7f121868; // 2131892328
public static final int microgsett = 0x7f121869; // 2131892329
public static final int monettheme_summ = 0x7f12186a; // 2131892330
public static final int monettheme_title = 0x7f12186b; // 2131892331
public static final int newsfeed_notif_summ = 0x7f12186c; // 2131892332
public static final int newsfeed_notif_title = 0x7f12186d; // 2131892333
public static final int open_bot = 0x7f12186e; // 2131892334
public static final int promotedstickers_title = 0x7f12186f; // 2131892335
public static final int remove_encryption_key = 0x7f121870; // 2131892336
public static final int remove_from_ads_stories_whitelist = 0x7f121871; // 2131892337
public static final int reset_accounts = 0x7f121872; // 2131892338
public static final int reset_all_settings = 0x7f121873; // 2131892339
public static final int restore_accounts = 0x7f121874; // 2131892340
public static final int restore_settings = 0x7f121875; // 2131892341
public static final int save_accounts = 0x7f121876; // 2131892342
public static final int save_online_data = 0x7f121877; // 2131892343
public static final int select_color = 0x7f121878; // 2131892344
public static final int select_palette = 0x7f121879; // 2131892345
public static final int sources = 0x7f12187a; // 2131892346
public static final int storiesGroupsAdBlock = 0x7f12187b; // 2131892347
public static final int storiesGroupsAdBlocksummary = 0x7f12187c; // 2131892348
public static final int systemtheme = 0x7f12187d; // 2131892349
public static final int systemtheme_enabled = 0x7f12187e; // 2131892350
public static final int systemtheme_summ = 0x7f12187f; // 2131892351
public static final int updateverifdata_summ = 0x7f121880; // 2131892352
public static final int updateverifdata_title = 0x7f121881; // 2131892353
public static final int useCustomPrefsStyle_summ = 0x7f121882; // 2131892354
public static final int useCustomPrefsStyle_title = 0x7f121883; // 2131892355
public static final int useGenius_summ = 0x7f121884; // 2131892356
public static final int useGenius_title = 0x7f121885; // 2131892357
public static final int useNewColorEngine_summ = 0x7f121886; // 2131892358
public static final int useNewColorEngine_title = 0x7f121887; // 2131892359
public static final int useOldAppVer_summ = 0x7f121888; // 2131892360
public static final int useOldAppVer_title = 0x7f121889; // 2131892361
public static final int vkx_integration_enabled_info = 0x7f12188a; // 2131892362
public static final int whitelisted_ad_groups_stories_title = 0x7f12188b; // 2131892363
public static final int writebar_ios_title = 0x7f12188c; // 2131892364
public static final int cache_size = 0x7f12188d; // 2131892365
public static final int cache_size_summ = 0x7f12188e; // 2131892366
public static final int clear_all_cache = 0x7f12188f; // 2131892367
public static final int disable_roaming_state = 0x7f121890; // 2131892368
public static final int disable_roaming_state_submit = 0x7f121891; // 2131892369
public static final int invalidate_theme_cache_each_update_title = 0x7f121892; // 2131892370
public static final int invertFilters = 0x7f121893; // 2131892371
public static final int invertFilters_summ = 0x7f121894; // 2131892372
public static final int invertcached_summ = 0x7f121895; // 2131892373
public static final int invertcached_title = 0x7f121896; // 2131892374
public static final int microg_dialog1 = 0x7f121897; // 2131892375
public static final int microg_dialog2 = 0x7f121898; // 2131892376
public static final int microg_dialog3 = 0x7f121899; // 2131892377
public static final int serverFeaturesDisable = 0x7f12189a; // 2131892378
public static final int serverFeaturesDisable_summ = 0x7f12189b; // 2131892379
public static final int sett_autoupdates = 0x7f12189c; // 2131892380
public static final int sett_autoupdates_summ = 0x7f12189d; // 2131892381
public static final int sett_battery = 0x7f12189e; // 2131892382
public static final int sett_battery_summ1 = 0x7f12189f; // 2131892383
public static final int sett_battery_summ2 = 0x7f1218a0; // 2131892384
public static final int sett_chats = 0x7f1218a1; // 2131892385
public static final int sett_chats_summ = 0x7f1218a2; // 2131892386
public static final int sett_community = 0x7f1218a3; // 2131892387
public static final int sett_community_summ = 0x7f1218a4; // 2131892388
public static final int sett_missing_links = 0x7f1218a5; // 2131892389
public static final int sett_missing_links_summ = 0x7f1218a6; // 2131892390
public static final int sett_nogms_summ = 0x7f1218a7; // 2131892391
public static final int sett_notifs = 0x7f1218a8; // 2131892392
public static final int sett_notifs_summ = 0x7f1218a9; // 2131892393
public static final int sett_recommendations = 0x7f1218aa; // 2131892394
public static final int tgs_token_missing = 0x7f1218ab; // 2131892395
public static final int tgs_token_reset = 0x7f1218ac; // 2131892396
public static final int tgs_token_reset_dialog = 0x7f1218ad; // 2131892397
public static final int tgs_token_reset_menu = 0x7f1218ae; // 2131892398
public static final int update_err = 0x7f1218af; // 2131892399
public static final int update_latest = 0x7f1218b0; // 2131892400
} }
public static final class style { public static final class style {
@@ -20890,6 +20786,5 @@ public final class R {
public static final int preferences_proxy = 0x7f15001c; // 2132082716 public static final int preferences_proxy = 0x7f15001c; // 2132082716
public static final int preferences_tgs = 0x7f15001d; // 2132082717 public static final int preferences_tgs = 0x7f15001d; // 2132082717
public static final int preferences_themes = 0x7f15001e; // 2132082718 public static final int preferences_themes = 0x7f15001e; // 2132082718
public static final int locales_config = 0x7f15001f; // 2132082719
} }
} }

Some files were not shown because too many files have changed in this diff Show More