Compare commits
72
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a85b3a4f0 | ||
|
|
413701d28e | ||
|
|
016bd342c4 | ||
|
|
d04b2249f0 | ||
|
|
8eb7ded6ba | ||
|
|
1f9c6fd80c | ||
|
|
4ec84e3754 | ||
|
|
ad3f70f4ac | ||
|
|
611f4d3159 | ||
|
|
7319714140 | ||
|
|
857db4879a | ||
|
|
b5db820733 | ||
|
|
c668105003 | ||
|
|
dd6bbcbc2c | ||
|
|
4ed0749027 | ||
|
|
3b834c2688 | ||
|
|
0c5a40bedc | ||
|
|
8146b863b1 | ||
|
|
c64f8a1b2d | ||
|
|
dd6916c08a | ||
|
|
58c14fbd4f | ||
|
|
3b830f5e2e | ||
|
|
c304313be9 | ||
|
|
3068ff76c1 | ||
|
|
a6b56e0e87 | ||
|
|
5360ca6c5e | ||
|
|
f2ac845797 | ||
|
|
a85e55a594 | ||
|
|
e2775db4e5 | ||
|
|
589e8928a0 | ||
|
|
cd189b1dda | ||
|
|
14c111a3e6 | ||
|
|
b506c56346 | ||
|
|
bbbc94e510 | ||
|
|
8cb2c380e7 | ||
|
|
b9879f9ed7 | ||
|
|
cf05e051e8 | ||
|
|
963c4d81ba | ||
|
|
099c699702 | ||
|
|
1117fc19d4 | ||
|
|
78dca26063 | ||
|
|
f5180f61d5 | ||
|
|
540fffdcc9 | ||
|
|
5357c60eaa | ||
|
|
c59f29121f | ||
|
|
bd38cab377 | ||
|
|
0058431590 | ||
|
|
bf4cf2be53 | ||
|
|
aac86a9952 | ||
|
|
ae00e72bac | ||
|
|
fea984f6fd | ||
|
|
d870c2f984 | ||
|
|
f7f43928cf | ||
|
|
1accb45f12 | ||
|
|
d9f53920e5 | ||
|
|
76d91332d7 | ||
|
|
728cbde683 | ||
|
|
60c98cd998 | ||
|
|
f1d106e0f0 | ||
|
|
c92194e90b | ||
|
|
91683af807 | ||
|
|
c5c898aa4e | ||
|
|
25634b2469 | ||
|
|
b8e764d09d | ||
|
|
17ed32857a | ||
|
|
d631d07e0f | ||
|
|
2ec4c69832 | ||
|
|
6426c965c6 | ||
|
|
4f6d410185 | ||
|
|
18a899f439 | ||
|
|
7e5b3fe233 | ||
|
|
4abd0eec6c |
@@ -0,0 +1,28 @@
|
||||
<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>
|
||||
@@ -0,0 +1,17 @@
|
||||
<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>
|
||||
@@ -0,0 +1,17 @@
|
||||
<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>
|
||||
@@ -0,0 +1,24 @@
|
||||
<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>
|
||||
@@ -0,0 +1,24 @@
|
||||
<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>
|
||||
@@ -0,0 +1,24 @@
|
||||
<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>
|
||||
@@ -0,0 +1,24 @@
|
||||
<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>
|
||||
@@ -0,0 +1,24 @@
|
||||
<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>
|
||||
@@ -0,0 +1,24 @@
|
||||
<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>
|
||||
@@ -0,0 +1,24 @@
|
||||
<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>
|
||||
@@ -0,0 +1,24 @@
|
||||
<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>
|
||||
@@ -0,0 +1,24 @@
|
||||
<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>
|
||||
@@ -0,0 +1,24 @@
|
||||
<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>
|
||||
@@ -0,0 +1,24 @@
|
||||
<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>
|
||||
@@ -0,0 +1,24 @@
|
||||
<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>
|
||||
@@ -0,0 +1,24 @@
|
||||
<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>
|
||||
@@ -0,0 +1,24 @@
|
||||
<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>
|
||||
+41
-38
@@ -20,9 +20,9 @@ cargo {
|
||||
def smaliFolder = projectDir.toPath().resolve("../smali").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()
|
||||
def dexes = smaliFolder.toFile()
|
||||
.listFiles({ f -> f.isDirectory() && f.name.startsWith("smali") } as FileFilter)
|
||||
.size()
|
||||
|
||||
versionFile {
|
||||
file = projectDir.toPath().resolve("src/main/assets/version.properties").toFile()
|
||||
@@ -78,18 +78,24 @@ android {
|
||||
targetCompatibility JavaVersion.VERSION_14
|
||||
}
|
||||
namespace 'ru.vtosters.lite'
|
||||
ndkVersion '25.2.9519653'
|
||||
ndkVersion '26.1.10909125'
|
||||
buildFeatures {
|
||||
aidl true
|
||||
}
|
||||
}
|
||||
|
||||
task testClasses {
|
||||
doLast {
|
||||
println 'This is a dummy testClasses task'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.microsoft.appcenter:appcenter-analytics:5.0.1'
|
||||
implementation 'com.microsoft.appcenter:appcenter-crashes:5.0.1'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
|
||||
implementation 'com.microsoft.appcenter:appcenter-analytics:5.0.4'
|
||||
implementation 'com.microsoft.appcenter:appcenter-crashes:5.0.4'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
|
||||
implementation 'net.sourceforge.streamsupport:streamsupport-minifuture:1.7.4'
|
||||
implementation 'com.google.guava:guava:23.3-android'
|
||||
implementation 'com.google.guava:guava:32.0.0-android'
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.aar'])
|
||||
compileOnly fileTree(dir: 'libs', include: ['*.jar'])
|
||||
@@ -99,38 +105,35 @@ task generateBuildTasks() {
|
||||
android.applicationVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
def buildType = output.name.toString().capitalize()
|
||||
if(buildType=="Base")return
|
||||
if (buildType == "Base") return
|
||||
task "exportDex$buildType"() {
|
||||
dependsOn('assemble' + buildType)
|
||||
doLast {
|
||||
try {
|
||||
def suffix=buildType.toLowerCase()
|
||||
String apkPath=projectDir.getAbsolutePath()+"/build/outputs/apk/$suffix/app-$suffix"
|
||||
def apk=new File(apkPath+"-unsigned.apk")
|
||||
if(!apk.exists())apk=new File(apkPath+".apk")
|
||||
def zip=new ZipFile(apk)
|
||||
def entries=zip.entries()
|
||||
def dexCounter=dexes
|
||||
while(entries.hasMoreElements())
|
||||
{
|
||||
def entry=entries.nextElement()
|
||||
String filename
|
||||
if(entry.name.matches("^classes(?:(?=\\d)2|)\\.dex\$"))filename="classes${++dexCounter}.dex"
|
||||
else if(entry.name=="assets/version.properties")filename="version.properties"
|
||||
else continue
|
||||
println("Exporting "+entry.name)
|
||||
def tmpFile=new File(projectDir,filename)
|
||||
def is=zip.getInputStream(entry)
|
||||
def fos=new FileOutputStream(tmpFile)
|
||||
def buff=new byte[0x800]
|
||||
int len
|
||||
while((len=is.read(buff))>0)fos.write(buff,0,len)
|
||||
is.close()
|
||||
fos.close()
|
||||
}
|
||||
def suffix = buildType.toLowerCase()
|
||||
String apkPath = projectDir.getAbsolutePath() + "/build/outputs/apk/$suffix/app-$suffix"
|
||||
def apk = new File(apkPath + "-unsigned.apk")
|
||||
if (!apk.exists()) apk = new File(apkPath + ".apk")
|
||||
def zip = new ZipFile(apk)
|
||||
def dexCounter = dexes
|
||||
zip.stream()
|
||||
.filter(entry -> entry.name.matches("^classes(?:(?=\\d)2|)\\.dex\$") || entry.name == "assets/version.properties")
|
||||
.forEach(entry -> {
|
||||
String filename
|
||||
if (entry.name.matches("^classes(?:(?=\\d)2|)\\.dex\$")) filename = "classes${++dexCounter}.dex"
|
||||
else filename = "version.properties"
|
||||
println("Exporting " + entry.name)
|
||||
def tmpFile = new File(projectDir, filename)
|
||||
try (def is = zip.getInputStream(entry); def fos = new FileOutputStream(tmpFile)) {
|
||||
def buff = new byte[0x800]
|
||||
int len
|
||||
while ((len = is.read(buff)) > 0) fos.write(buff, 0, len)
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
task "prepareDexForMerge$buildType"(type: Copy) {
|
||||
@@ -146,19 +149,19 @@ task generateBuildTasks() {
|
||||
include 'version.properties'
|
||||
into 'assets'
|
||||
}
|
||||
from('../native-effects/target/aarch64-linux-android/release'){
|
||||
from('../native-effects/target/aarch64-linux-android/release') {
|
||||
include 'libnative_effects.so'
|
||||
into 'lib/arm64-v8a'
|
||||
}
|
||||
from('../native-effects/target/armv7-linux-androideabi/release'){
|
||||
from('../native-effects/target/armv7-linux-androideabi/release') {
|
||||
include 'libnative_effects.so'
|
||||
into 'lib/armeabi-v7a'
|
||||
}
|
||||
}
|
||||
task "cleanTemporaryFiles$buildType"(type:Delete)
|
||||
task "cleanTemporaryFiles$buildType"(type: Delete)
|
||||
{
|
||||
delete fileTree(dir:projectDir,include:["*.dex","version.properties"])
|
||||
delete fileTree(dir:smaliFolder,include:['*.dex',"assets/version.properties"])
|
||||
delete fileTree(dir: projectDir, include: ["*.dex", "version.properties"])
|
||||
delete fileTree(dir: smaliFolder, include: ['*.dex', "assets/version.properties"])
|
||||
}
|
||||
task "buildVTL$buildType"(type: Exec) {
|
||||
dependsOn('prepareDexForMerge' + buildType)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -6,13 +6,14 @@ import android.os.RemoteException;
|
||||
import bruhcollective.itaysonlab.libvkx.ILibVkxService;
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import com.vk.music.common.MusicPlaybackLaunchContext;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
import static ru.vtosters.hooks.other.Preferences.isValidSignature;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
|
||||
public class LibVKXClient {
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
@@ -33,7 +34,7 @@ public class LibVKXClient {
|
||||
public static boolean isVkxInstalled() {
|
||||
try {
|
||||
getGlobalContext().getPackageManager().getPackageInfo("ua.itaysonlab.vkx", 0);
|
||||
return isValidSignature();
|
||||
return isValidSignature() && !Preferences.serverFeaturesDisable();
|
||||
} catch (Exception unused) {
|
||||
return false;
|
||||
}
|
||||
@@ -81,10 +82,6 @@ public class LibVKXClient {
|
||||
}
|
||||
|
||||
public static String asId(MusicTrack musicTrack) {
|
||||
String id = musicTrack.e + "_" + musicTrack.d;
|
||||
if (musicTrack.O != null && !musicTrack.O.equals("")) {
|
||||
id += "_" + musicTrack.O;
|
||||
}
|
||||
return id;
|
||||
return musicTrack.y1();
|
||||
}
|
||||
}
|
||||
@@ -36,8 +36,8 @@ public class TelegramStickersPack extends CustomStickersPack {
|
||||
public HashMap<String, List<Integer>> emojis = new HashMap<>();
|
||||
|
||||
public TelegramStickersPack(String id) {
|
||||
this.id=this.title=id;
|
||||
this.hash=id.hashCode();
|
||||
this.id = this.title = id;
|
||||
this.hash = id.hashCode();
|
||||
}
|
||||
|
||||
public JSONObject encodeEmojis() throws JSONException {
|
||||
|
||||
@@ -26,19 +26,13 @@ import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
public class TelegramStickersService {
|
||||
private static final String TAG = "TGStickersService";
|
||||
private static TelegramStickersService instance;
|
||||
|
||||
private final Context c;
|
||||
|
||||
private final ArrayList<TelegramStickersPack> packs;
|
||||
private final ArrayList<TelegramStickersPack> activePacks;
|
||||
private final ArrayList<TelegramStickersPack> inactivePacks;
|
||||
private final ArrayList<StickersEventsListener> listeners;
|
||||
private final HashSet<String> currentlyDownloading;
|
||||
|
||||
private final Handler uiThreadHandler;
|
||||
|
||||
private final TelegramStickersGrabber grabber;
|
||||
|
||||
private final TelegramStickersDbHelper dbHelper;
|
||||
private final ArrayList<Runnable> queuedTasks;
|
||||
private final ThreadPoolExecutor executor;
|
||||
@@ -48,16 +42,14 @@ public class TelegramStickersService {
|
||||
private TelegramStickersService(Context context) {
|
||||
instance = this;
|
||||
|
||||
this.c = context.getApplicationContext();
|
||||
|
||||
listeners = new ArrayList<>();
|
||||
currentlyDownloading = new HashSet<>();
|
||||
uiThreadHandler = new Handler(Looper.getMainLooper());
|
||||
grabber = new TelegramStickersGrabber(null);
|
||||
dbHelper = new TelegramStickersDbHelper(c);
|
||||
dbHelper = new TelegramStickersDbHelper(context);
|
||||
queuedTasks = new ArrayList<>();
|
||||
executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
|
||||
notificationsHelper = new NotificationsHelper(c);
|
||||
notificationsHelper = new NotificationsHelper(context);
|
||||
|
||||
packs = new ArrayList<>();
|
||||
activePacks = new ArrayList<>();
|
||||
@@ -70,11 +62,11 @@ public class TelegramStickersService {
|
||||
return instance == null ? new TelegramStickersService(c) : instance;
|
||||
}
|
||||
|
||||
private void updatePacks(final boolean notify) {
|
||||
private void updatePacks(boolean notify) {
|
||||
packs.clear();
|
||||
dbHelper.getAllPacks(new TelegramStickersDbHelper.PacksLoadingListener() {
|
||||
@Override
|
||||
public void onPackLoaded(final TelegramStickersPack pack) {
|
||||
public void onPackLoaded(TelegramStickersPack pack) {
|
||||
runOnUiThread(() -> {
|
||||
packs.add(pack);
|
||||
|
||||
@@ -103,14 +95,6 @@ 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) {
|
||||
getGlobalContext().sendBroadcast(new Intent(StickersFragment.ACTION_RELOAD));
|
||||
if (listeners.isEmpty())
|
||||
@@ -188,20 +172,16 @@ public class TelegramStickersService {
|
||||
return inactivePacks;
|
||||
}
|
||||
|
||||
public boolean isDoneLoading() {
|
||||
return ready;
|
||||
}
|
||||
|
||||
public boolean requestPackDownload(final String id, File packFolder) {
|
||||
public void requestPackDownload(String id, File packFolder) {
|
||||
if (currentlyDownloading.contains(id)) {
|
||||
Log.e(TAG, String.format("Got request to download pack %s which is already downloading", id));
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ready) {
|
||||
final File folder = packFolder;
|
||||
File folder = packFolder;
|
||||
queuedTasks.add(() -> requestPackDownload(id, folder));
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
TelegramStickersPack pack = new TelegramStickersPack(id);
|
||||
@@ -221,85 +201,86 @@ public class TelegramStickersService {
|
||||
notifyPackAdded(pack, packs.size() - 1);
|
||||
}
|
||||
|
||||
final TelegramStickersPack newPack = pack;
|
||||
final boolean isUpdate = update;
|
||||
TelegramStickersPack newPack = pack;
|
||||
boolean isUpdate = update;
|
||||
|
||||
currentlyDownloading.add(id);
|
||||
notificationsHelper.packStartedDownloading(newPack);
|
||||
|
||||
|
||||
grabber.enableProxy();
|
||||
grabber.grabPack(id, packFolder, pack.version, new TelegramStickersGrabber.PackDownloadListener() {
|
||||
@Override
|
||||
public void onPackDownloaded(TelegramStickersPackInfo packInfo, boolean newVersionFound) {
|
||||
|
||||
runOnUiThread(() -> {
|
||||
newPack.state = TelegramStickersPack.DOWNLOADED;
|
||||
notifyPackChanged(newPack, packs.indexOf(newPack));
|
||||
currentlyDownloading.remove(newPack.id);
|
||||
syncPack(newPack);
|
||||
|
||||
if (isUpdate) {
|
||||
if (newPack.enabled)
|
||||
notifyActivePacksListChanged();
|
||||
} else {
|
||||
activePacks.add(newPack);
|
||||
notifyActivePacksListChanged();
|
||||
}
|
||||
});
|
||||
notificationsHelper.packDoneDownloading(newPack, true, isUpdate, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackDownloadError(final Exception e) {
|
||||
runOnUiThread(() -> {
|
||||
Log.e(TAG, "Error while downloading pack " + newPack.id);
|
||||
e.printStackTrace();
|
||||
|
||||
if (!isUpdate) {
|
||||
int index = packs.indexOf(newPack);
|
||||
packs.remove(index);
|
||||
notifyPackRemoved(newPack, index);
|
||||
} else {
|
||||
// try-catch block to handle possible timeout exception
|
||||
try {
|
||||
grabber.grabPack(id, packFolder, pack.version, new TelegramStickersGrabber.PackDownloadListener() {
|
||||
@Override
|
||||
public void onPackDownloaded(TelegramStickersPackInfo packInfo, boolean newVersionFound) {
|
||||
runOnUiThread(() -> {
|
||||
newPack.state = TelegramStickersPack.DOWNLOADED;
|
||||
notifyPackChanged(newPack, packs.indexOf(newPack));
|
||||
}
|
||||
currentlyDownloading.remove(newPack.id);
|
||||
syncPack(newPack);
|
||||
|
||||
notifyPackDownloadError(newPack, e);
|
||||
currentlyDownloading.remove(newPack.id);
|
||||
});
|
||||
notificationsHelper.packDoneDownloading(newPack, false, isUpdate, e);
|
||||
}
|
||||
if (isUpdate) {
|
||||
if (newPack.enabled)
|
||||
notifyActivePacksListChanged();
|
||||
} else {
|
||||
activePacks.add(newPack);
|
||||
notifyActivePacksListChanged();
|
||||
}
|
||||
});
|
||||
notificationsHelper.packDoneDownloading(newPack, true, isUpdate, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGotPackInfo(final TelegramStickersPackInfo packInfo) {
|
||||
runOnUiThread(() -> {
|
||||
newPack.title = packInfo.title;
|
||||
newPack.stickersCount = packInfo.stickersCount;
|
||||
newPack.version = packInfo.version;
|
||||
notifyPackChanged(newPack, packs.indexOf(newPack));
|
||||
});
|
||||
@Override
|
||||
public void onPackDownloadError(Exception e) {
|
||||
runOnUiThread(() -> {
|
||||
Log.e(TAG, "Error while downloading pack " + newPack.id);
|
||||
e.printStackTrace();
|
||||
|
||||
notificationsHelper.packDownloadUpdated(newPack, 0);
|
||||
}
|
||||
if (!isUpdate) {
|
||||
int index = packs.indexOf(newPack);
|
||||
packs.remove(index);
|
||||
notifyPackRemoved(newPack, index);
|
||||
} else {
|
||||
newPack.state = TelegramStickersPack.DOWNLOADED;
|
||||
notifyPackChanged(newPack, packs.indexOf(newPack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStickerDownloaded(String pack, File sticker, String boundEmoji, int stickerIndex, int downloadedStickersCount, int totalStickersCount) {
|
||||
stickerIndex--;
|
||||
notifyPackDownloadError(newPack, e);
|
||||
currentlyDownloading.remove(newPack.id);
|
||||
});
|
||||
notificationsHelper.packDoneDownloading(newPack, false, isUpdate, e);
|
||||
}
|
||||
|
||||
List<Integer> list = newPack.emojis.get(boundEmoji);
|
||||
if (list == null) list = new ArrayList<>();
|
||||
list.add(stickerIndex);
|
||||
newPack.emojis.put(boundEmoji, list);
|
||||
@Override
|
||||
public void onGotPackInfo(TelegramStickersPackInfo packInfo) {
|
||||
runOnUiThread(() -> {
|
||||
newPack.title = packInfo.title;
|
||||
newPack.stickersCount = packInfo.stickersCount;
|
||||
newPack.version = packInfo.version;
|
||||
notifyPackChanged(newPack, packs.indexOf(newPack));
|
||||
});
|
||||
|
||||
notificationsHelper.packDownloadUpdated(newPack, downloadedStickersCount);
|
||||
}
|
||||
});
|
||||
notificationsHelper.packDownloadUpdated(newPack, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
@Override
|
||||
public void onStickerDownloaded(String pack, File sticker, String boundEmoji, int stickerIndex, int downloadedStickersCount, int totalStickersCount) {
|
||||
stickerIndex--;
|
||||
|
||||
List<Integer> list = newPack.emojis.get(boundEmoji);
|
||||
if (list == null) list = new ArrayList<>();
|
||||
list.add(stickerIndex);
|
||||
newPack.emojis.put(boundEmoji, list);
|
||||
|
||||
notificationsHelper.packDownloadUpdated(newPack, downloadedStickersCount);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
// handle other possible exceptions
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void setPackEnabled(final TelegramStickersPack pack, final boolean enabled, final boolean notify) {
|
||||
public void setPackEnabled(TelegramStickersPack pack, boolean enabled, boolean notify) {
|
||||
if (!ready) {
|
||||
queuedTasks.add(() -> setPackEnabled(pack, enabled, notify));
|
||||
return;
|
||||
@@ -325,7 +306,7 @@ public class TelegramStickersService {
|
||||
}
|
||||
}
|
||||
|
||||
public void deletePack(final TelegramStickersPack pack) {
|
||||
public void deletePack(TelegramStickersPack pack) {
|
||||
if (!ready) {
|
||||
queuedTasks.add(() -> deletePack(pack));
|
||||
return;
|
||||
@@ -334,7 +315,6 @@ public class TelegramStickersService {
|
||||
boolean d = dbHelper.deletePack(pack);
|
||||
Log.d(TAG, "Delete from DB=" + d);
|
||||
|
||||
|
||||
int index = packs.indexOf(pack);
|
||||
packs.remove(index);
|
||||
notifyPackRemoved(pack, index);
|
||||
@@ -355,7 +335,7 @@ public class TelegramStickersService {
|
||||
uiThreadHandler.post(r);
|
||||
}
|
||||
|
||||
private void syncPack(final TelegramStickersPack pack) {
|
||||
private void syncPack(TelegramStickersPack pack) {
|
||||
if (!ready) {
|
||||
queuedTasks.add(() -> syncPack(pack));
|
||||
return;
|
||||
@@ -397,6 +377,4 @@ public class TelegramStickersService {
|
||||
|
||||
void onInactivePacksListChanged();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -7,23 +7,20 @@ import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import com.aefyr.tsg.g2.stickersgrabber.util.Flag;
|
||||
import com.aefyr.tsg.g2.stickersgrabber.util.GoalCounter;
|
||||
import okhttp3.*;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.net.*;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.net.Proxy;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
@@ -31,14 +28,19 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
*/
|
||||
public class TelegramStickersGrabber {
|
||||
private static final String TAG = "TSG";
|
||||
public static String REAL_TG_IP = null;
|
||||
public static String PROXY_IP = null;
|
||||
public static int PROXY_PORT = -1;
|
||||
public static String PROXY_USER = null;
|
||||
public static String PROXY_PASS = null;
|
||||
public static boolean PROXY_SOCKS = true;
|
||||
public static boolean HAS_PASS = false;
|
||||
public static boolean USE_PROXY = false;
|
||||
private static final OkHttpClient sClient = VtOkHttpClient.getInstance();
|
||||
private static final int MAX_RETRIES = 2;
|
||||
private static final AtomicInteger retryCount = new AtomicInteger();
|
||||
private static final int STICKER_QUALITY = 100;
|
||||
private static final String STICKER_FILE_NAME_FORMAT = "%03d.png";
|
||||
private static final String STICKERS_KEY = "stickers";
|
||||
private static final String FILE_ID_KEY = "file_id";
|
||||
private static final String EMOJI_KEY = "emoji";
|
||||
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 GET_STICKER_SET_URL;
|
||||
private static String GET_FILE_URL;
|
||||
@@ -50,12 +52,10 @@ public class TelegramStickersGrabber {
|
||||
|
||||
private final MessageDigest sha256;
|
||||
private final Handler uiThreadHandler;
|
||||
private String botApiKey = "";
|
||||
private NetClient httpClient;
|
||||
private String botApiKey;
|
||||
|
||||
public TelegramStickersGrabber(String botApiKey) {
|
||||
this.botApiKey = botApiKey;
|
||||
httpClient = new NetClient.Builder().connectTimeout(5, TimeUnit.SECONDS).build();
|
||||
uiThreadHandler = new Handler(Looper.getMainLooper());
|
||||
try {
|
||||
sha256 = MessageDigest.getInstance("SHA-256");
|
||||
@@ -69,81 +69,12 @@ public class TelegramStickersGrabber {
|
||||
public static void updateURLs() {
|
||||
BOT_API_BASE_FILE_URL = "https://api.telegram.org/file/bot%s/%s";
|
||||
|
||||
|
||||
BOT_API_BASE_URL = REAL_TG_IP != null ? "https://" + REAL_TG_IP + "/bot%s/" : "https://api.telegram.org/bot%s/";
|
||||
BOT_API_BASE_URL = "https://api.telegram.org/bot%s/";
|
||||
GET_STICKER_SET_URL = BOT_API_BASE_URL + "getStickerSet?name=%s";
|
||||
GET_FILE_URL = BOT_API_BASE_URL + "getFile?file_id=%s";
|
||||
}
|
||||
|
||||
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) {
|
||||
public void grabPack(String id, File packFolder, String installedVersion, PackDownloadListener listener) {
|
||||
getPackInfo(id, packFolder, installedVersion, listener);
|
||||
}
|
||||
|
||||
@@ -151,264 +82,247 @@ public class TelegramStickersGrabber {
|
||||
botApiKey = key;
|
||||
}
|
||||
|
||||
public void checkKey(final KeyCheckListener listener) {
|
||||
public void checkKey(KeyCheckListener listener) {
|
||||
Log.d(TAG, "Checking key: " + botApiKey);
|
||||
NetRequest request = new NetRequest.Builder().get().url(String.format(BOT_API_BASE_URL + "getMe", botApiKey)).build();
|
||||
httpClient.newCall(request).enqueue(new NetCallback() {
|
||||
// Create a request object with the URL and bot API key
|
||||
Request request = new Request.a()
|
||||
.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
|
||||
public void onFailure(NetCall call, IOException e) {
|
||||
e.printStackTrace();
|
||||
public void a(Call call, IOException e) {
|
||||
// Handle the failure case
|
||||
Log.d(TAG, e.getMessage());
|
||||
runOnUiThread(listener::onNetError);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(NetCall call, final NetResponse response) throws IOException {
|
||||
runOnUiThread(() -> listener.onKeyChecked(response.code() == 200));
|
||||
public void a(Call call, Response response) {
|
||||
Log.d(TAG, response.toString());
|
||||
runOnUiThread(() -> listener.onKeyChecked(response.h()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void getPackInfo(final String packName, final File packFolder, final String installedVersion, final PackDownloadListener listener) {
|
||||
NetRequest packInfoRequest = new NetRequest.Builder().get().url(String.format(GET_STICKER_SET_URL, botApiKey, packName)).build();
|
||||
httpClient.newCall(packInfoRequest).enqueue(new NetCallback() {
|
||||
private void getPack(StickerSet set, File packFolder, TelegramStickersPackInfo packInfo, PackDownloadListener listener) {
|
||||
GoalCounter downloadedStickers = new GoalCounter(set.stickers.size(), () -> {
|
||||
Log.d(TAG, String.format("Pack %s has been downloaded to %s", set.id, packFolder.getAbsolutePath()));
|
||||
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
|
||||
public void a(Call call, IOException e) {
|
||||
handleFailure(deathFlag, listener, e, downloadedStickers, call, fileInfoRequest, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(Call call, Response response) {
|
||||
if (deathFlag.up())
|
||||
return;
|
||||
|
||||
if (!response.h()) {
|
||||
retryRequest(call, fileInfoRequest, this);
|
||||
return;
|
||||
}
|
||||
|
||||
try (ResponseBody responseBody = response.a()) {
|
||||
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 {
|
||||
saveStickerImage(stickerImage, stickerFile);
|
||||
} catch (TSGException e) {
|
||||
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 onFailure(NetCall call, IOException e) {
|
||||
public void a(Call call, IOException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
listener.onPackDownloadError(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(NetCall call, NetResponse response) {
|
||||
if (!response.isSuccessful()) {
|
||||
if (response.getData() != null)
|
||||
listener.onPackDownloadError(new TSGException(response.getDataString() + "\nURL: " + call.request().url()));
|
||||
else
|
||||
listener.onPackDownloadError(new TSGException("Unknown Exception, no response body"));
|
||||
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;
|
||||
}
|
||||
|
||||
StickerSet set;
|
||||
try {
|
||||
JSONObject jPackInfo = new JSONObject(response.getDataString()).getJSONObject("result");
|
||||
String packVersion = new String(sha256.digest(jPackInfo.toString().getBytes(StandardCharsets.UTF_8)));
|
||||
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)) {
|
||||
listener.onPackDownloaded(null, false);
|
||||
return;
|
||||
}
|
||||
|
||||
JSONArray jStickers = jPackInfo.getJSONArray("stickers");
|
||||
JSONArray stickersArray = packInfoResponse.getJSONArray(STICKERS_KEY);
|
||||
|
||||
if (jStickers.length() == 0) {
|
||||
if (stickersArray.length() == 0) {
|
||||
listener.onPackDownloadError(new TSGException("No stickers in pack"));
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<Sticker> stickers = new ArrayList<>(jStickers.length());
|
||||
ArrayList<Sticker> stickers = parseStickers(stickersArray);
|
||||
|
||||
Log.d(TAG, String.format("Parsing stickers in pack %s", packName));
|
||||
StickerSet set = new StickerSet(packInfoResponse.getString(NAME_KEY), packInfoResponse.getString(TITLE_KEY), packVersion, stickers);
|
||||
|
||||
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")));
|
||||
}
|
||||
if (!packFolder.exists() && !packFolder.mkdirs()) {
|
||||
// Handle the folder creation failure case
|
||||
listener.onPackDownloadError(new IOException("Can't create folder for the pack!"));
|
||||
return;
|
||||
}
|
||||
|
||||
set = new StickerSet(jPackInfo.getString("name"), jPackInfo.getString("title"), packVersion, stickers);
|
||||
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);
|
||||
|
||||
listener.onGotPackInfo(packInfo);
|
||||
|
||||
getPack(set, packFolder, packInfo, listener);
|
||||
} catch (Exception e) {
|
||||
listener.onPackDownloadError(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!packFolder.exists() && !packFolder.mkdirs()) {
|
||||
listener.onPackDownloadError(new IOException("Can't create folder for the pack!"));
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
listener.onGotPackInfo(packInfo);
|
||||
getPack(set, packFolder, packInfo, listener);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void getPack(final StickerSet set, final File packFolder, final TelegramStickersPackInfo packInfo, final PackDownloadListener listener) {
|
||||
final GoalCounter downloadedStickers = new GoalCounter(set.stickers.size(), () -> {
|
||||
Log.d(TAG, String.format("Pack %s has been downloaded to %s", set.id, packFolder.getAbsolutePath()));
|
||||
private ArrayList<Sticker> parseStickers(JSONArray stickersArray) throws JSONException, TSGException {
|
||||
ArrayList<Sticker> stickers = new ArrayList<>(stickersArray.length());
|
||||
|
||||
listener.onPackDownloaded(packInfo, true);
|
||||
});
|
||||
final Flag deathFlag = new Flag();
|
||||
for (int i = 0; i < stickersArray.length(); i++) {
|
||||
JSONObject stickerObject = stickersArray.getJSONObject(i);
|
||||
boolean isAnimated = stickerObject.optBoolean(IS_ANIMATED_KEY);
|
||||
boolean isVideo = stickerObject.optBoolean(IS_VIDEO_KEY);
|
||||
String fileId = stickerObject.getString(FILE_ID_KEY);
|
||||
String emoji = stickerObject.getString(EMOJI_KEY);
|
||||
|
||||
AtomicInteger retryed = new AtomicInteger();
|
||||
for (int i = 0; i < set.stickers.size(); i++) {
|
||||
final Sticker sticker = set.stickers.get(i);
|
||||
NetRequest fileInfoRequest = new NetRequest.Builder().get().url(String.format(GET_FILE_URL, botApiKey, sticker.fileId)).build();
|
||||
|
||||
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);
|
||||
if (isAnimated || isVideo) {
|
||||
if (stickerObject.has(THUMB_KEY)) {
|
||||
fileId = stickerObject.getJSONObject(THUMB_KEY).getString(FILE_ID_KEY);
|
||||
} else {
|
||||
throw new TSGException("Animated and video stickerpacks without thumbs are not supported!");
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
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) {
|
||||
}
|
||||
stickers.add(new Sticker(fileId, emoji));
|
||||
}
|
||||
|
||||
return stickers;
|
||||
}
|
||||
|
||||
private void runOnUiThread(Runnable r) {
|
||||
@@ -431,15 +345,13 @@ public class TelegramStickersGrabber {
|
||||
void onNetError();
|
||||
}
|
||||
|
||||
public class TSGException extends Exception {
|
||||
private static final long serialVersionUID = 7866915509988422944L;
|
||||
|
||||
public static class TSGException extends Exception {
|
||||
private TSGException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
private class StickerSet {
|
||||
private static class StickerSet {
|
||||
String id;
|
||||
String name;
|
||||
String version;
|
||||
@@ -453,7 +365,7 @@ public class TelegramStickersGrabber {
|
||||
}
|
||||
}
|
||||
|
||||
private class Sticker {
|
||||
private static class Sticker {
|
||||
String emoji;
|
||||
String fileId;
|
||||
|
||||
|
||||
@@ -59,26 +59,22 @@ public class ArscBlamer {
|
||||
* Maps type chunk entries to blamed resources.
|
||||
*/
|
||||
private final Multimap<TypeChunk.Entry, ResourceEntry> typeEntryToBlame = HashMultimap.create();
|
||||
|
||||
/**
|
||||
* Maps resources to the type chunk entries they reference.
|
||||
*/
|
||||
private Multimap<ResourceEntry, TypeChunk.Entry> resourceEntries;
|
||||
|
||||
/**
|
||||
* Maps resources which have no base config to the type chunk entries they reference.
|
||||
*/
|
||||
private Multimap<ResourceEntry, TypeChunk.Entry> baselessKeys;
|
||||
|
||||
/**
|
||||
* Contains all of the type chunks in {@link #resourceTable}.
|
||||
*/
|
||||
private List<TypeChunk> typeChunks;
|
||||
|
||||
/**
|
||||
* This is the {@link ResourceTableChunk} inside of the resources.arsc file in the APK.
|
||||
*/
|
||||
private final ResourceTableChunk resourceTable;
|
||||
/**
|
||||
* Maps resources to the type chunk entries they reference.
|
||||
*/
|
||||
private Multimap<ResourceEntry, TypeChunk.Entry> resourceEntries;
|
||||
/**
|
||||
* Maps resources which have no base config to the type chunk entries they reference.
|
||||
*/
|
||||
private Multimap<ResourceEntry, TypeChunk.Entry> baselessKeys;
|
||||
/**
|
||||
* Contains all of the type chunks in {@link #resourceTable}.
|
||||
*/
|
||||
private List<TypeChunk> typeChunks;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ArscBlamer}.
|
||||
@@ -90,6 +86,14 @@ public class ArscBlamer {
|
||||
this.stringToBlame = createEntryListArray(resourceTable.getStringPool().getStringCount());
|
||||
}
|
||||
|
||||
private static List<ResourceEntry>[] createEntryListArray(int size) {
|
||||
ArrayListResourceEntry[] result = new ArrayListResourceEntry[size];
|
||||
for (int i = 0; i < size; ++i) {
|
||||
result[i] = new ArrayListResourceEntry();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates blame mappings.
|
||||
*/
|
||||
@@ -257,14 +261,6 @@ public class ArscBlamer {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static List<ResourceEntry>[] createEntryListArray(int size) {
|
||||
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}.
|
||||
*/
|
||||
@@ -283,6 +279,12 @@ public class ArscBlamer {
|
||||
private final String typeName;
|
||||
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) {
|
||||
PackageChunk packageChunk = Preconditions.checkNotNull(entry.parent().getPackageChunk());
|
||||
String packageName = packageChunk.getPackageName();
|
||||
@@ -291,12 +293,6 @@ public class ArscBlamer {
|
||||
return new ResourceEntry(packageName, typeName, entryName);
|
||||
}
|
||||
|
||||
private ResourceEntry(String packageName, String typeName, String entryName) {
|
||||
this.packageName = packageName;
|
||||
this.typeName = typeName;
|
||||
this.entryName = entryName;
|
||||
}
|
||||
|
||||
public String packageName() {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
+221
-240
@@ -31,6 +31,148 @@ import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
* Describes a particular resource configuration.
|
||||
*/
|
||||
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 mcc;
|
||||
private final int mnc;
|
||||
@@ -53,9 +195,60 @@ public class BinaryResourceConfiguration implements SerializableResource {
|
||||
private final int screenHeightDp;
|
||||
private final byte[] localeScript;
|
||||
private final byte[] localeVariant;
|
||||
// end - miui
|
||||
private final int screenLayout2;
|
||||
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) {
|
||||
int startPosition = buffer.position(); // The starting buffer position to calculate bytes read.
|
||||
int size = buffer.getInt();
|
||||
@@ -121,245 +314,6 @@ public class BinaryResourceConfiguration implements SerializableResource {
|
||||
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.
|
||||
*/
|
||||
@@ -708,7 +662,7 @@ public class BinaryResourceConfiguration implements SerializableResource {
|
||||
Map<Type, String> result = new LinkedHashMap<>(); // Preserve order for #toString().
|
||||
result.put(Type.MCC, mcc() != 0 ? "mcc" + mcc() : "");
|
||||
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.SCREEN_LAYOUT_DIRECTION,
|
||||
getOrDefault(SCREENLAYOUT_LAYOUTDIR_VALUES, screenLayoutDirection(), ""));
|
||||
@@ -742,4 +696,31 @@ public class BinaryResourceConfiguration implements SerializableResource {
|
||||
V value = map.get(key);
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -49,6 +49,12 @@ public class BinaryResourceIdentifier {
|
||||
private final int typeId;
|
||||
private final int entryId;
|
||||
|
||||
private BinaryResourceIdentifier(int packageId, int typeId, int entryId) {
|
||||
this.packageId = packageId;
|
||||
this.typeId = typeId;
|
||||
this.entryId = entryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link BinaryResourceIdentifier} from a {@code resourceId} of the form 0xpptteeee.
|
||||
*/
|
||||
@@ -69,12 +75,6 @@ public class BinaryResourceIdentifier {
|
||||
return new BinaryResourceIdentifier(packageId, typeId, entryId);
|
||||
}
|
||||
|
||||
private BinaryResourceIdentifier(int packageId, int typeId, int entryId) {
|
||||
this.packageId = packageId;
|
||||
this.typeId = typeId;
|
||||
this.entryId = entryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* The (1-based) id of the {@link PackageChunk} containing this resource.
|
||||
*/
|
||||
|
||||
+18
-18
@@ -31,24 +31,6 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
*/
|
||||
public final class BinaryResourceString {
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
private BinaryResourceString() {
|
||||
} // Private constructor
|
||||
|
||||
@@ -166,4 +148,22 @@ public final class BinaryResourceString {
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+77
-79
@@ -31,6 +31,78 @@ import java.util.Objects;
|
||||
*/
|
||||
public class BinaryResourceValue implements SerializableResource {
|
||||
|
||||
/**
|
||||
* The serialized size in bytes of a {@link BinaryResourceValue}.
|
||||
*/
|
||||
public static final int SIZE = 8;
|
||||
public int size;
|
||||
public Type type;
|
||||
public int data;
|
||||
public BinaryResourceValue(int size, Type type, int data) {
|
||||
this.size = size;
|
||||
this.type = type;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public static BinaryResourceValue create(ByteBuffer buffer) {
|
||||
int size = (buffer.getShort() & 0xFFFF);
|
||||
buffer.get(); // Unused
|
||||
Type type = Type.fromCode(buffer.get());
|
||||
int data = buffer.getInt();
|
||||
return new BinaryResourceValue(size, type, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The length in bytes of this value.
|
||||
*/
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* The raw data type of this value.
|
||||
*/
|
||||
public Type type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual 4-byte value; interpretation of the value depends on {@code dataType}.
|
||||
*/
|
||||
public int data() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return toByteArray(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray(boolean shrink) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(SIZE).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.putShort((short) size());
|
||||
buffer.put((byte) 0); // Unused
|
||||
buffer.put(type().code());
|
||||
buffer.putInt(data());
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
BinaryResourceValue that = (BinaryResourceValue) o;
|
||||
return size == that.size &&
|
||||
data == that.data &&
|
||||
type == that.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(size, type, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resource type codes.
|
||||
*/
|
||||
@@ -100,8 +172,6 @@ public class BinaryResourceValue implements SerializableResource {
|
||||
*/
|
||||
INT_COLOR_RGB4(0x1f);
|
||||
|
||||
private final byte code;
|
||||
|
||||
private static final Map<Byte, Type> FROM_BYTE;
|
||||
|
||||
static {
|
||||
@@ -112,90 +182,18 @@ public class BinaryResourceValue implements SerializableResource {
|
||||
FROM_BYTE = builder.build();
|
||||
}
|
||||
|
||||
private final byte code;
|
||||
|
||||
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;
|
||||
|
||||
public int size;
|
||||
public Type type;
|
||||
public int data;
|
||||
|
||||
public static BinaryResourceValue create(ByteBuffer buffer) {
|
||||
int size = (buffer.getShort() & 0xFFFF);
|
||||
buffer.get(); // Unused
|
||||
Type type = Type.fromCode(buffer.get());
|
||||
int data = buffer.getInt();
|
||||
return new BinaryResourceValue(size, type, data);
|
||||
}
|
||||
|
||||
public BinaryResourceValue(int size, Type type, int data) {
|
||||
this.size = size;
|
||||
this.type = type;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* The length in bytes of this value.
|
||||
*/
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* The raw data type of this value.
|
||||
*/
|
||||
public Type type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual 4-byte value; interpretation of the value depends on {@code dataType}.
|
||||
*/
|
||||
public int data() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return toByteArray(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray(boolean shrink) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(SIZE).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.putShort((short) size());
|
||||
buffer.put((byte) 0); // Unused
|
||||
buffer.put(type().code());
|
||||
buffer.putInt(data());
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
BinaryResourceValue that = (BinaryResourceValue) o;
|
||||
return size == that.size &&
|
||||
data == that.data &&
|
||||
type == that.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(size, type, data);
|
||||
public byte code() {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,86 +35,36 @@ import java.util.Map;
|
||||
*/
|
||||
public abstract class Chunk implements SerializableResource {
|
||||
|
||||
/**
|
||||
* 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 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;
|
||||
|
||||
/**
|
||||
* The number of bytes in every chunk that describes chunk type, header size, and chunk size.
|
||||
*/
|
||||
public static final int METADATA_SIZE = 8;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* The parent to this chunk, if any.
|
||||
*/
|
||||
@Nullable
|
||||
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) {
|
||||
this.parent = parent;
|
||||
offset = buffer.position() - 2;
|
||||
@@ -122,6 +72,74 @@ public abstract class Chunk implements SerializableResource {
|
||||
chunkSize = buffer.getInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new chunk whose contents start at {@code buffer}'s current position.
|
||||
*
|
||||
* @param buffer A buffer positioned at the start of a chunk.
|
||||
* @return new chunk
|
||||
*/
|
||||
public static Chunk newInstance(ByteBuffer buffer) {
|
||||
return newInstance(buffer, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new chunk whose contents start at {@code buffer}'s current position.
|
||||
*
|
||||
* @param buffer A buffer positioned at the start of a chunk.
|
||||
* @param parent The parent to this chunk (or null if there's no parent).
|
||||
* @return new chunk
|
||||
*/
|
||||
public static Chunk newInstance(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
Chunk result;
|
||||
Type type = Type.fromCode(buffer.getShort());
|
||||
switch (type) {
|
||||
case STRING_POOL:
|
||||
result = new StringPoolChunk(buffer, parent);
|
||||
break;
|
||||
case TABLE:
|
||||
result = new ResourceTableChunk(buffer, parent);
|
||||
break;
|
||||
case XML:
|
||||
result = new XmlChunk(buffer, parent);
|
||||
break;
|
||||
case XML_START_NAMESPACE:
|
||||
result = new XmlNamespaceStartChunk(buffer, parent);
|
||||
break;
|
||||
case XML_END_NAMESPACE:
|
||||
result = new XmlNamespaceEndChunk(buffer, parent);
|
||||
break;
|
||||
case XML_START_ELEMENT:
|
||||
result = new XmlStartElementChunk(buffer, parent);
|
||||
break;
|
||||
case XML_END_ELEMENT:
|
||||
result = new XmlEndElementChunk(buffer, parent);
|
||||
break;
|
||||
case XML_CDATA:
|
||||
result = new XmlCdataChunk(buffer, parent);
|
||||
break;
|
||||
case XML_RESOURCE_MAP:
|
||||
result = new XmlResourceMapChunk(buffer, parent);
|
||||
break;
|
||||
case TABLE_PACKAGE:
|
||||
result = new PackageChunk(buffer, parent);
|
||||
break;
|
||||
case TABLE_TYPE:
|
||||
result = new TypeChunk(buffer, parent);
|
||||
break;
|
||||
case TABLE_TYPE_SPEC:
|
||||
result = new TypeSpecChunk(buffer, parent);
|
||||
break;
|
||||
case TABLE_LIBRARY:
|
||||
result = new LibraryChunk(buffer, parent);
|
||||
break;
|
||||
default:
|
||||
result = new UnknownChunk(buffer, parent);
|
||||
}
|
||||
result.init(buffer);
|
||||
result.seekToEndOfChunk(buffer);
|
||||
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
|
||||
@@ -256,70 +274,46 @@ public abstract class Chunk implements SerializableResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new chunk whose contents start at {@code buffer}'s current position.
|
||||
*
|
||||
* @param buffer A buffer positioned at the start of a chunk.
|
||||
* @return new chunk
|
||||
* Types of chunks that can exist.
|
||||
*/
|
||||
public static Chunk newInstance(ByteBuffer buffer) {
|
||||
return newInstance(buffer, null);
|
||||
}
|
||||
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);
|
||||
|
||||
/**
|
||||
* Creates a new chunk whose contents start at {@code buffer}'s current position.
|
||||
*
|
||||
* @param buffer A buffer positioned at the start of a chunk.
|
||||
* @param parent The parent to this chunk (or null if there's no parent).
|
||||
* @return new chunk
|
||||
*/
|
||||
public static Chunk newInstance(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
Chunk result;
|
||||
Type type = Type.fromCode(buffer.getShort());
|
||||
switch (type) {
|
||||
case STRING_POOL:
|
||||
result = new StringPoolChunk(buffer, parent);
|
||||
break;
|
||||
case TABLE:
|
||||
result = new ResourceTableChunk(buffer, parent);
|
||||
break;
|
||||
case XML:
|
||||
result = new XmlChunk(buffer, parent);
|
||||
break;
|
||||
case XML_START_NAMESPACE:
|
||||
result = new XmlNamespaceStartChunk(buffer, parent);
|
||||
break;
|
||||
case XML_END_NAMESPACE:
|
||||
result = new XmlNamespaceEndChunk(buffer, parent);
|
||||
break;
|
||||
case XML_START_ELEMENT:
|
||||
result = new XmlStartElementChunk(buffer, parent);
|
||||
break;
|
||||
case XML_END_ELEMENT:
|
||||
result = new XmlEndElementChunk(buffer, parent);
|
||||
break;
|
||||
case XML_CDATA:
|
||||
result = new XmlCdataChunk(buffer, parent);
|
||||
break;
|
||||
case XML_RESOURCE_MAP:
|
||||
result = new XmlResourceMapChunk(buffer, parent);
|
||||
break;
|
||||
case TABLE_PACKAGE:
|
||||
result = new PackageChunk(buffer, parent);
|
||||
break;
|
||||
case TABLE_TYPE:
|
||||
result = new TypeChunk(buffer, parent);
|
||||
break;
|
||||
case TABLE_TYPE_SPEC:
|
||||
result = new TypeSpecChunk(buffer, parent);
|
||||
break;
|
||||
case TABLE_LIBRARY:
|
||||
result = new LibraryChunk(buffer, parent);
|
||||
break;
|
||||
default:
|
||||
result = new UnknownChunk(buffer, parent);
|
||||
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;
|
||||
}
|
||||
result.init(buffer);
|
||||
result.seekToEndOfChunk(buffer);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public final class LibraryChunk extends Chunk {
|
||||
*/
|
||||
private final List<Entry> entries = new ArrayList<>();
|
||||
|
||||
protected LibraryChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
LibraryChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
super(buffer, parent);
|
||||
entryCount = buffer.getInt();
|
||||
}
|
||||
@@ -98,17 +98,17 @@ public final class LibraryChunk extends Chunk {
|
||||
private final int packageId;
|
||||
private final String packageName;
|
||||
|
||||
private Entry(int packageId, String packageName) {
|
||||
this.packageId = packageId;
|
||||
this.packageName = packageName;
|
||||
}
|
||||
|
||||
static Entry create(ByteBuffer buffer, int offset) {
|
||||
int packageId = buffer.getInt(offset);
|
||||
String packageName = PackageUtils.readPackageName(buffer, offset + 4);
|
||||
return new Entry(packageId, packageName);
|
||||
}
|
||||
|
||||
private Entry(int packageId, String packageName) {
|
||||
this.packageId = packageId;
|
||||
this.packageName = packageName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The id assigned to the shared library at build time.
|
||||
*/
|
||||
|
||||
@@ -43,58 +43,48 @@ public final class PackageChunk extends ChunkWithChunks {
|
||||
* Offset in bytes, from the start of the chunk, where {@code keyStringsOffset} can be found.
|
||||
*/
|
||||
private static final int KEY_OFFSET_OFFSET = 276;
|
||||
|
||||
/**
|
||||
* The package id if this is a base package, or 0 if not a base package.
|
||||
*/
|
||||
private int id;
|
||||
|
||||
/**
|
||||
* The name of the package.
|
||||
*/
|
||||
private String packageName;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* The package id if this is a base package, or 0 if not a base package.
|
||||
*/
|
||||
private int id;
|
||||
/**
|
||||
* The name of the package.
|
||||
*/
|
||||
private String packageName;
|
||||
/**
|
||||
* May contain a library chunk for mapping dynamic references to resolved references.
|
||||
*/
|
||||
private Optional<LibraryChunk> libraryChunk = Optional.empty();
|
||||
|
||||
protected PackageChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
PackageChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
super(buffer, parent);
|
||||
id = buffer.getInt();
|
||||
packageName = PackageUtils.readPackageName(buffer, buffer.position());
|
||||
|
||||
@@ -36,17 +36,16 @@ import java.util.Map;
|
||||
*/
|
||||
public final class ResourceTableChunk extends ChunkWithChunks {
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The packages contained in this resource table.
|
||||
*/
|
||||
private final Map<String, PackageChunk> packages = new HashMap<>();
|
||||
|
||||
protected ResourceTableChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
ResourceTableChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
super(buffer, parent);
|
||||
// packageCount. We ignore this, because we already know how many chunks we have.
|
||||
Preconditions.checkState(buffer.getInt() >= 1, "ResourceTableChunk package count was < 1.");
|
||||
|
||||
@@ -89,7 +89,7 @@ public final class StringPoolChunk extends Chunk {
|
||||
*/
|
||||
private boolean isOriginalDeduped = false;
|
||||
|
||||
protected StringPoolChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
StringPoolChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
super(buffer, parent);
|
||||
stringCount = buffer.getInt();
|
||||
styleCount = buffer.getInt();
|
||||
@@ -310,6 +310,10 @@ public final class StringPoolChunk extends Chunk {
|
||||
static final int RES_STRING_POOL_SPAN_END = 0xFFFFFFFF;
|
||||
private final List<StringPoolSpan> spans;
|
||||
|
||||
private StringPoolStyle(List<StringPoolSpan> spans) {
|
||||
this.spans = spans;
|
||||
}
|
||||
|
||||
static StringPoolStyle create(ByteBuffer buffer, int offset, StringPoolChunk parent) {
|
||||
Builder<StringPoolSpan> spans = ImmutableList.builder();
|
||||
int nameIndex = buffer.getInt(offset);
|
||||
@@ -321,10 +325,6 @@ public final class StringPoolChunk extends Chunk {
|
||||
return new StringPoolStyle(spans.build());
|
||||
}
|
||||
|
||||
private StringPoolStyle(List<StringPoolSpan> spans) {
|
||||
this.spans = spans;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() throws IOException {
|
||||
return toByteArray(false);
|
||||
@@ -384,13 +384,6 @@ public final class StringPoolChunk extends Chunk {
|
||||
private final int stop;
|
||||
private final StringPoolChunk parent;
|
||||
|
||||
static StringPoolSpan create(ByteBuffer buffer, int offset, StringPoolChunk parent) {
|
||||
int nameIndex = buffer.getInt(offset);
|
||||
int start = buffer.getInt(offset + 4);
|
||||
int stop = buffer.getInt(offset + 8);
|
||||
return new StringPoolSpan(nameIndex, start, stop, parent);
|
||||
}
|
||||
|
||||
private StringPoolSpan(int nameIndex, int start, int stop, StringPoolChunk parent) {
|
||||
this.nameIndex = nameIndex;
|
||||
this.start = start;
|
||||
@@ -398,6 +391,13 @@ public final class StringPoolChunk extends Chunk {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
static StringPoolSpan create(ByteBuffer buffer, int offset, StringPoolChunk parent) {
|
||||
int nameIndex = buffer.getInt(offset);
|
||||
int start = buffer.getInt(offset + 4);
|
||||
int stop = buffer.getInt(offset + 8);
|
||||
return new StringPoolSpan(nameIndex, start, stop, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final byte[] toByteArray() {
|
||||
return toByteArray(false);
|
||||
|
||||
@@ -52,18 +52,16 @@ public final class TypeChunk extends Chunk {
|
||||
* The offset (from {@code offset}) in the original buffer where {@code entries} start.
|
||||
*/
|
||||
private final int entriesStart;
|
||||
|
||||
/**
|
||||
* A sparse list of resource entries defined by this chunk.
|
||||
*/
|
||||
private final Map<Integer, Entry> entries = new TreeMap<>();
|
||||
/**
|
||||
* The resource configuration that these resource entries correspond to.
|
||||
*/
|
||||
private BinaryResourceConfiguration configuration;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
TypeChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
super(buffer, parent);
|
||||
id = UnsignedBytes.toInt(buffer.get());
|
||||
buffer.position(buffer.position() + 3); // Skip 3 bytes for packing
|
||||
@@ -176,13 +174,13 @@ public final class TypeChunk extends Chunk {
|
||||
}
|
||||
}
|
||||
|
||||
protected String getString(int index) {
|
||||
private String getString(int index) {
|
||||
ResourceTableChunk resourceTable = getResourceTableChunk();
|
||||
Preconditions.checkNotNull(resourceTable, "%s has no resource table.", getClass());
|
||||
return resourceTable.getStringPool().getString(index);
|
||||
}
|
||||
|
||||
protected String getKeyName(int index) {
|
||||
private String getKeyName(int index) {
|
||||
PackageChunk packageChunk = getPackageChunk();
|
||||
Preconditions.checkNotNull(packageChunk, "%s has no parent package.", getClass());
|
||||
StringPoolChunk keyPool = packageChunk.getKeyStringPool();
|
||||
@@ -190,7 +188,7 @@ public final class TypeChunk extends Chunk {
|
||||
return keyPool.getString(index);
|
||||
}
|
||||
|
||||
protected void updateKey(int index, String value) {
|
||||
private void updateKey(int index, String value) {
|
||||
PackageChunk packageChunk = getPackageChunk();
|
||||
Preconditions.checkNotNull(packageChunk, "%s has no parent package.", getClass());
|
||||
StringPoolChunk keyPool = packageChunk.getKeyStringPool();
|
||||
@@ -293,10 +291,10 @@ public final class TypeChunk extends Chunk {
|
||||
private final int headerSize;
|
||||
private final int flags;
|
||||
private final int keyIndex;
|
||||
private BinaryResourceValue value;
|
||||
private Map<Integer, BinaryResourceValue> values;
|
||||
private final int parentEntry;
|
||||
private final TypeChunk parent;
|
||||
private BinaryResourceValue value;
|
||||
private final Map<Integer, BinaryResourceValue> values;
|
||||
|
||||
private Entry(int headerSize,
|
||||
int flags,
|
||||
@@ -314,6 +312,52 @@ public final class TypeChunk extends Chunk {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 baseOffset}. If the value read from {@code buffer} is equal to {@link #NO_ENTRY}, then
|
||||
* null is returned as there is no resource at that position.
|
||||
*
|
||||
* <p>Otherwise, this position is parsed and returned as an {@link Entry}.
|
||||
*
|
||||
* @param buffer A buffer positioned at an offset to an {@link Entry}.
|
||||
* @param baseOffset Offset that must be added to the value at {@code buffer}'s position.
|
||||
* @param parent The {@link TypeChunk} that this resource entry belongs to.
|
||||
* @return New {@link Entry} or null if there is no resource at this location.
|
||||
*/
|
||||
@Nullable
|
||||
public static Entry create(ByteBuffer buffer, int baseOffset, TypeChunk parent) {
|
||||
int offset = buffer.getInt();
|
||||
if (offset == NO_ENTRY) {
|
||||
return null;
|
||||
}
|
||||
int position = buffer.position();
|
||||
buffer.position(baseOffset + offset); // Set buffer position to resource entry start
|
||||
Entry result = newInstance(buffer, parent);
|
||||
buffer.position(position); // Restore buffer position
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Entry newInstance(ByteBuffer buffer, TypeChunk parent) {
|
||||
int headerSize = buffer.getShort() & 0xFFFF;
|
||||
int flags = buffer.getShort() & 0xFFFF;
|
||||
int keyIndex = buffer.getInt();
|
||||
BinaryResourceValue value = null;
|
||||
Map<Integer, BinaryResourceValue> values = new LinkedHashMap<>();
|
||||
int parentEntry = 0;
|
||||
if ((flags & FLAG_COMPLEX) != 0) {
|
||||
parentEntry = buffer.getInt();
|
||||
int valueCount = buffer.getInt();
|
||||
for (int i = 0; i < valueCount; ++i) {
|
||||
values.put(buffer.getInt(), BinaryResourceValue.create(buffer));
|
||||
}
|
||||
} else {
|
||||
value = BinaryResourceValue.create(buffer);
|
||||
}
|
||||
return new Entry(headerSize, flags, keyIndex, value, values, parentEntry, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of bytes in the header of the {@link Entry}.
|
||||
*/
|
||||
@@ -422,52 +466,6 @@ public final class TypeChunk extends Chunk {
|
||||
return (flags() & FLAG_COMPLEX) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 baseOffset}. If the value read from {@code buffer} is equal to {@link #NO_ENTRY}, then
|
||||
* null is returned as there is no resource at that position.
|
||||
*
|
||||
* <p>Otherwise, this position is parsed and returned as an {@link Entry}.
|
||||
*
|
||||
* @param buffer A buffer positioned at an offset to an {@link Entry}.
|
||||
* @param baseOffset Offset that must be added to the value at {@code buffer}'s position.
|
||||
* @param parent The {@link TypeChunk} that this resource entry belongs to.
|
||||
* @return New {@link Entry} or null if there is no resource at this location.
|
||||
*/
|
||||
@Nullable
|
||||
public static Entry create(ByteBuffer buffer, int baseOffset, TypeChunk parent) {
|
||||
int offset = buffer.getInt();
|
||||
if (offset == NO_ENTRY) {
|
||||
return null;
|
||||
}
|
||||
int position = buffer.position();
|
||||
buffer.position(baseOffset + offset); // Set buffer position to resource entry start
|
||||
Entry result = newInstance(buffer, parent);
|
||||
buffer.position(position); // Restore buffer position
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Entry newInstance(ByteBuffer buffer, TypeChunk parent) {
|
||||
int headerSize = buffer.getShort() & 0xFFFF;
|
||||
int flags = buffer.getShort() & 0xFFFF;
|
||||
int keyIndex = buffer.getInt();
|
||||
BinaryResourceValue value = null;
|
||||
Map<Integer, BinaryResourceValue> values = new LinkedHashMap<>();
|
||||
int parentEntry = 0;
|
||||
if ((flags & FLAG_COMPLEX) != 0) {
|
||||
parentEntry = buffer.getInt();
|
||||
int valueCount = buffer.getInt();
|
||||
for (int i = 0; i < valueCount; ++i) {
|
||||
values.put(buffer.getInt(), BinaryResourceValue.create(buffer));
|
||||
}
|
||||
} else {
|
||||
value = BinaryResourceValue.create(buffer);
|
||||
}
|
||||
return new Entry(headerSize, flags, keyIndex, value, values, parentEntry, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final byte[] toByteArray() {
|
||||
return toByteArray(false);
|
||||
|
||||
@@ -39,7 +39,7 @@ public final class TypeSpecChunk extends Chunk {
|
||||
*/
|
||||
private final int[] resources;
|
||||
|
||||
protected TypeSpecChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
TypeSpecChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
super(buffer, parent);
|
||||
id = UnsignedBytes.toInt(buffer.get());
|
||||
buffer.position(buffer.position() + 3); // Skip 3 bytes for packing
|
||||
|
||||
@@ -34,7 +34,7 @@ public final class UnknownChunk extends Chunk {
|
||||
|
||||
private final byte[] payload;
|
||||
|
||||
protected UnknownChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
UnknownChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
super(buffer, parent);
|
||||
|
||||
type = Type.fromCode(buffer.getShort(offset));
|
||||
|
||||
@@ -36,6 +36,18 @@ public class XmlAttribute implements SerializableResource {
|
||||
private final BinaryResourceValue typedValue;
|
||||
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.
|
||||
*
|
||||
@@ -50,18 +62,6 @@ public class XmlAttribute implements SerializableResource {
|
||||
return new XmlAttribute(namespace, name, rawValue, typedValue, 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* A string reference to the namespace URI, or -1 if not present.
|
||||
*/
|
||||
|
||||
@@ -37,7 +37,7 @@ public final class XmlCdataChunk extends XmlNodeChunk {
|
||||
*/
|
||||
private final BinaryResourceValue binaryResourceValue;
|
||||
|
||||
protected XmlCdataChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
XmlCdataChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
super(buffer, parent);
|
||||
rawValue = buffer.getInt();
|
||||
binaryResourceValue = BinaryResourceValue.create(buffer);
|
||||
|
||||
@@ -28,7 +28,7 @@ import java.nio.ByteBuffer;
|
||||
*/
|
||||
public final class XmlChunk extends ChunkWithChunks {
|
||||
|
||||
protected XmlChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
XmlChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
super(buffer, parent);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ public final class XmlEndElementChunk extends XmlNodeChunk {
|
||||
*/
|
||||
private final int name;
|
||||
|
||||
protected XmlEndElementChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
XmlEndElementChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
super(buffer, parent);
|
||||
namespace = buffer.getInt();
|
||||
name = buffer.getInt();
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import java.nio.ByteBuffer;
|
||||
*/
|
||||
public final class XmlNamespaceEndChunk extends XmlNamespaceChunk {
|
||||
|
||||
protected XmlNamespaceEndChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
XmlNamespaceEndChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
super(buffer, parent);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import java.nio.ByteBuffer;
|
||||
*/
|
||||
public final class XmlNamespaceStartChunk extends XmlNamespaceChunk {
|
||||
|
||||
protected XmlNamespaceStartChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
XmlNamespaceStartChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
super(buffer, parent);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ public final class XmlStartElementChunk extends XmlNodeChunk {
|
||||
*/
|
||||
private final List<XmlAttribute> attributes = new ArrayList<>();
|
||||
|
||||
protected XmlStartElementChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
XmlStartElementChunk(ByteBuffer buffer, @Nullable Chunk parent) {
|
||||
super(buffer, parent);
|
||||
namespace = buffer.getInt();
|
||||
name = buffer.getInt();
|
||||
|
||||
@@ -6,9 +6,9 @@ import com.vk.api.base.ApiRequest;
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import com.vk.log.L;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.music.Genius;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -25,7 +25,7 @@ public class AudioGetLyrics extends ApiRequest<AudioGetLyrics.a> {
|
||||
public a a(@NonNull JSONObject jSONObject) {
|
||||
var aVar = new a();
|
||||
|
||||
if (Preferences.getBoolValue("useGenius", false)) {
|
||||
if (Preferences.getBoolValue("useGenius", false) && !Preferences.serverFeaturesDisable()) {
|
||||
aVar.a = Genius.getTextMusic(musicTrack);
|
||||
return aVar;
|
||||
}
|
||||
|
||||
@@ -7,16 +7,6 @@ import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
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) {
|
||||
super("execute.getGiftByStickerId");
|
||||
b("sticker_id", i);
|
||||
@@ -30,4 +20,14 @@ public class GiftGetByStickerId extends ApiRequest<GiftGetByStickerId.a> {
|
||||
return new a(jSONObject2.optInt("balance"),
|
||||
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,6 +27,15 @@ public class RecoloredDrawable extends Drawable implements Drawable.Callback {
|
||||
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) {
|
||||
a(new ColorStateList(new int[][]{new int[0]}, new int[]{i}));
|
||||
}
|
||||
@@ -120,13 +129,4 @@ public class RecoloredDrawable extends Drawable implements Drawable.Callback {
|
||||
public Drawable a() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,13 @@ public final class VerifyInfoHelper {
|
||||
public static final VerifyInfoHelper h;
|
||||
public static int devIcon = R.drawable.ic_favorite_16;
|
||||
|
||||
static {
|
||||
h = new VerifyInfoHelper();
|
||||
}
|
||||
|
||||
private VerifyInfoHelper() {
|
||||
}
|
||||
|
||||
public static Integer enumSwitchMapping(VerifyInfoHelper.ColorTheme color) {
|
||||
return switch (color) {
|
||||
case normal -> 1;
|
||||
@@ -30,18 +37,47 @@ public final class VerifyInfoHelper {
|
||||
};
|
||||
}
|
||||
|
||||
public enum ColorTheme {
|
||||
white,
|
||||
normal,
|
||||
light,
|
||||
ultraLight
|
||||
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);
|
||||
}
|
||||
|
||||
static {
|
||||
h = new VerifyInfoHelper();
|
||||
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);
|
||||
}
|
||||
|
||||
private VerifyInfoHelper() {
|
||||
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 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() {
|
||||
@@ -89,7 +125,6 @@ public final class VerifyInfoHelper {
|
||||
return b(this, z, z2, false, context, null, 8, null);
|
||||
}
|
||||
|
||||
|
||||
public int b(ColorTheme colorTheme) {
|
||||
return a(colorTheme);
|
||||
}
|
||||
@@ -104,7 +139,6 @@ public final class VerifyInfoHelper {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public Drawable b(Context context, VerifyInfo verifyInfo) {
|
||||
if (verifyInfo.dev()) {
|
||||
return new RecoloredDrawable(ContextCompat.getDrawable(context, devIcon), c(ColorTheme.normal));
|
||||
@@ -123,21 +157,6 @@ public final class VerifyInfoHelper {
|
||||
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) {
|
||||
if (verifyInfo.dev()) {
|
||||
return new RecoloredDrawable(ContextCompat.getDrawable(context, devIcon), c(ColorTheme.normal));
|
||||
@@ -181,28 +200,10 @@ public final class VerifyInfoHelper {
|
||||
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) {
|
||||
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) {
|
||||
return a(z, z2, false, context, colorTheme);
|
||||
}
|
||||
@@ -230,16 +231,6 @@ public final class VerifyInfoHelper {
|
||||
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) {
|
||||
Drawable drawable;
|
||||
Context context = textView.getContext();
|
||||
@@ -267,4 +258,11 @@ public final class VerifyInfoHelper {
|
||||
}
|
||||
ViewExtKt.p(imageView);
|
||||
}
|
||||
|
||||
public enum ColorTheme {
|
||||
white,
|
||||
normal,
|
||||
light,
|
||||
ultraLight
|
||||
}
|
||||
}
|
||||
+25
-25
@@ -31,30 +31,6 @@ public final class DialogGetMentionSuggestionCmd extends BaseImEngineCmd<Suggest
|
||||
private final boolean e;
|
||||
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) {
|
||||
this.f2365b = i;
|
||||
this.c = str;
|
||||
@@ -150,7 +126,7 @@ public final class DialogGetMentionSuggestionCmd extends BaseImEngineCmd<Suggest
|
||||
Collection<Member> a2;
|
||||
Source source;
|
||||
if (ImDialogsUtils.d(this.f2365b) != PeerType.CHAT) {
|
||||
return new Suggestion((EntityValue) null, (ProfilesInfo) null);
|
||||
return new Suggestion(null, null);
|
||||
}
|
||||
Member Z = imEnvironment.Z();
|
||||
int d = imEnvironment.a0().n().d();
|
||||
@@ -235,4 +211,28 @@ public final class DialogGetMentionSuggestionCmd extends BaseImEngineCmd<Suggest
|
||||
public String toString() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import java.util.List;
|
||||
public final class DialogActionsHelper {
|
||||
public static final DialogActionsHelper a = new DialogActionsHelper();
|
||||
|
||||
public final List<DialogAction> a(ImConfig imConfig, Dialog dialog, ProfilesSimpleInfo profilesSimpleInfo) {
|
||||
public List<DialogAction> a(ImConfig imConfig, Dialog dialog, ProfilesSimpleInfo profilesSimpleInfo) {
|
||||
if (dialog != null && profilesSimpleInfo != null) {
|
||||
long b2 = TimeProvider.f.b();
|
||||
ChatSettings z1 = dialog.z1();
|
||||
@@ -84,7 +84,7 @@ public final class DialogActionsHelper {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
public final List<DialogAction> a(Dialog dialog, ProfilesSimpleInfo profilesSimpleInfo) {
|
||||
public List<DialogAction> a(Dialog dialog, ProfilesSimpleInfo profilesSimpleInfo) {
|
||||
long b2 = TimeProvider.f.b();
|
||||
Profile profile = profilesSimpleInfo.get(dialog.getId());
|
||||
|
||||
@@ -138,7 +138,7 @@ public final class DialogActionsHelper {
|
||||
return arrayList;
|
||||
}
|
||||
|
||||
public final boolean a(Dialog dialog) {
|
||||
public boolean a(Dialog dialog) {
|
||||
if (dialog.V1() || !dialog.y1()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@ import java.util.List;
|
||||
public final class MsgActionHelper {
|
||||
public static final MsgActionHelper a = new MsgActionHelper();
|
||||
|
||||
public final List<MsgAction> a(ImEngine imEngine, Dialog dialog, Collection<? extends Msg> collection) {
|
||||
public List<MsgAction> a(ImEngine imEngine, Dialog dialog, Collection<? extends Msg> collection) {
|
||||
return a(imEngine != null ? imEngine.g() : null, dialog, collection);
|
||||
}
|
||||
|
||||
public final List<MsgAction> a(ImConfig imConfig, Dialog dialog, Collection<? extends Msg> collection) {
|
||||
public List<MsgAction> a(ImConfig imConfig, Dialog dialog, Collection<? extends Msg> collection) {
|
||||
if (imConfig != null && dialog != null && collection != null) {
|
||||
MsgPermissionHelper.a aVar = new MsgPermissionHelper.a(imConfig, dialog, collection);
|
||||
ArrayList<MsgAction> arrayList = new ArrayList<>();
|
||||
|
||||
+29
-137
@@ -74,11 +74,7 @@ public class VhBindArgs {
|
||||
|
||||
private boolean L() {
|
||||
boolean var1;
|
||||
if (this.K() <= this.m && !TimeProvider.f.c()) {
|
||||
var1 = false;
|
||||
} else {
|
||||
var1 = true;
|
||||
}
|
||||
var1 = this.K() > this.m || TimeProvider.f.c();
|
||||
|
||||
return var1;
|
||||
}
|
||||
@@ -109,11 +105,7 @@ public class VhBindArgs {
|
||||
public boolean B() {
|
||||
AdapterEntry var1 = this.a;
|
||||
boolean var2;
|
||||
if (var1 != null && var1.c()) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 != null && var1.c();
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -121,11 +113,7 @@ public class VhBindArgs {
|
||||
public boolean C() {
|
||||
AdapterEntry var1 = this.a;
|
||||
boolean var2;
|
||||
if (var1 != null && var1.c() && this.a.c.getLocalId() == this.b.c.getLocalId()) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 != null && var1.c() && this.a.c.getLocalId() == this.b.c.getLocalId();
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -133,11 +121,7 @@ public class VhBindArgs {
|
||||
public boolean D() {
|
||||
AdapterEntry var1 = this.a;
|
||||
boolean var2;
|
||||
if (var1 != null && var1.a == 83) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 != null && var1.a == 83;
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -145,11 +129,7 @@ public class VhBindArgs {
|
||||
public boolean E() {
|
||||
Msg var1 = this.b.c;
|
||||
boolean var2;
|
||||
if (var1 instanceof MsgFromUser && ((MsgFromUser) var1).i2()) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 instanceof MsgFromUser && ((MsgFromUser) var1).i2();
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -157,11 +137,7 @@ public class VhBindArgs {
|
||||
public boolean F() {
|
||||
Msg var1 = this.b.c;
|
||||
boolean var2;
|
||||
if (var1 instanceof MsgFromUser && ((MsgFromUser) var1).F0()) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 instanceof MsgFromUser && ((MsgFromUser) var1).F0();
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -169,11 +145,7 @@ public class VhBindArgs {
|
||||
public boolean G() {
|
||||
AdapterEntry var1 = this.b;
|
||||
boolean var2;
|
||||
if (var1 != null && var1.a == 51) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 != null && var1.a == 51;
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -186,11 +158,7 @@ public class VhBindArgs {
|
||||
long var1 = this.K();
|
||||
long var3 = this.m;
|
||||
boolean var5;
|
||||
if (var1 > var3 && var1 < var3 * 2L) {
|
||||
var5 = true;
|
||||
} else {
|
||||
var5 = false;
|
||||
}
|
||||
var5 = var1 > var3 && var1 < var3 * 2L;
|
||||
|
||||
return var5;
|
||||
}
|
||||
@@ -206,18 +174,10 @@ public class VhBindArgs {
|
||||
MsgFromUser var7 = (MsgFromUser) var1;
|
||||
Msg var3 = this.a.c;
|
||||
boolean var4;
|
||||
if (var3 != null && var3.d() == MsgSyncState.DONE) {
|
||||
var4 = true;
|
||||
} else {
|
||||
var4 = false;
|
||||
}
|
||||
var4 = var3 != null && var3.d() == MsgSyncState.DONE;
|
||||
|
||||
boolean var5;
|
||||
if (this.o == ImBgSyncState.CONNECTED) {
|
||||
var5 = true;
|
||||
} else {
|
||||
var5 = false;
|
||||
}
|
||||
var5 = this.o == ImBgSyncState.CONNECTED;
|
||||
|
||||
boolean var6 = var2;
|
||||
if (!var7.H0()) {
|
||||
@@ -242,7 +202,7 @@ public class VhBindArgs {
|
||||
byte var2 = 0;
|
||||
int var3 = var2;
|
||||
if (var1) {
|
||||
AttachAudioMsg var4 = (AttachAudioMsg) ((MsgFromUser) this.b.c).c(AttachAudioMsg.class, false);
|
||||
AttachAudioMsg var4 = ((MsgFromUser) this.b.c).c(AttachAudioMsg.class, false);
|
||||
var3 = var2;
|
||||
if (var4 != null) {
|
||||
var3 = var4.f();
|
||||
@@ -267,11 +227,7 @@ public class VhBindArgs {
|
||||
public boolean c() {
|
||||
Msg var1 = this.b.c;
|
||||
boolean var2;
|
||||
if (var1 instanceof MsgFromUser && ((MsgFromUser) var1).I0()) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 instanceof MsgFromUser && ((MsgFromUser) var1).I0();
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -279,22 +235,14 @@ public class VhBindArgs {
|
||||
public boolean d() {
|
||||
Msg var1 = this.b.c;
|
||||
boolean var2;
|
||||
if (var1 instanceof WithUserContent && ((WithUserContent) var1).D0() != null) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 instanceof WithUserContent && ((WithUserContent) var1).D0() != null;
|
||||
|
||||
return var2;
|
||||
}
|
||||
|
||||
public boolean e() {
|
||||
boolean var1;
|
||||
if (this.b.i > 0) {
|
||||
var1 = true;
|
||||
} else {
|
||||
var1 = false;
|
||||
}
|
||||
var1 = this.b.i > 0;
|
||||
|
||||
return var1;
|
||||
}
|
||||
@@ -317,11 +265,7 @@ public class VhBindArgs {
|
||||
public boolean g() {
|
||||
Msg var1 = this.b.c;
|
||||
boolean var2;
|
||||
if (var1 instanceof MsgFromUser && ((MsgFromUser) var1).G0()) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 instanceof MsgFromUser && ((MsgFromUser) var1).G0();
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -329,33 +273,21 @@ public class VhBindArgs {
|
||||
public boolean h() {
|
||||
Msg var1 = this.b.c;
|
||||
boolean var2;
|
||||
if (var1 instanceof MsgFromUser && ((MsgFromUser) var1).Z1()) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 instanceof MsgFromUser && ((MsgFromUser) var1).Z1();
|
||||
|
||||
return var2;
|
||||
}
|
||||
|
||||
public boolean i() {
|
||||
boolean var1;
|
||||
if (this.j && !this.u() && !this.l()) {
|
||||
var1 = true;
|
||||
} else {
|
||||
var1 = false;
|
||||
}
|
||||
var1 = this.j && !this.u() && !this.l();
|
||||
|
||||
return var1;
|
||||
}
|
||||
|
||||
public boolean j() {
|
||||
boolean var1;
|
||||
if (!this.j || this.u() || this.B() && this.A() && !this.a.c.H1()) {
|
||||
var1 = false;
|
||||
} else {
|
||||
var1 = true;
|
||||
}
|
||||
var1 = this.j && !this.u() && (!this.B() || !this.A() || this.a.c.H1());
|
||||
|
||||
return var1;
|
||||
}
|
||||
@@ -363,11 +295,7 @@ public class VhBindArgs {
|
||||
public boolean k() {
|
||||
Dialog var1 = this.e;
|
||||
boolean var2;
|
||||
if (var1 != null && var1.U1()) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 != null && var1.U1();
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -375,11 +303,7 @@ public class VhBindArgs {
|
||||
public boolean l() {
|
||||
Dialog var1 = this.e;
|
||||
boolean var2;
|
||||
if (var1 != null && var1.V1()) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 != null && var1.V1();
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -387,11 +311,7 @@ public class VhBindArgs {
|
||||
public boolean m() {
|
||||
Dialog var1 = this.e;
|
||||
boolean var2;
|
||||
if (var1 != null && var1.W1()) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 != null && var1.W1();
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -404,11 +324,7 @@ public class VhBindArgs {
|
||||
public boolean o() {
|
||||
AdapterEntry var1 = this.b;
|
||||
boolean var2;
|
||||
if (var1 != null && var1.a == 101) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 != null && var1.a == 101;
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -416,11 +332,7 @@ public class VhBindArgs {
|
||||
public boolean p() {
|
||||
Msg var1 = this.b.c;
|
||||
boolean var2;
|
||||
if (var1 != null && var1.G1()) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 != null && var1.G1();
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -443,11 +355,7 @@ public class VhBindArgs {
|
||||
public boolean r() {
|
||||
Msg var1 = this.b.c;
|
||||
boolean var2;
|
||||
if (var1 instanceof MsgFromUser && ((MsgFromUser) var1).e2()) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 instanceof MsgFromUser && ((MsgFromUser) var1).e2();
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -488,27 +396,19 @@ public class VhBindArgs {
|
||||
public boolean v() {
|
||||
IntSet var1 = this.r;
|
||||
boolean var2;
|
||||
if (var1 != null && var1.a(this.b.c.getLocalId())) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 != null && var1.a(this.b.c.getLocalId());
|
||||
|
||||
return var2;
|
||||
}
|
||||
|
||||
public boolean w() {
|
||||
return this.z() ^ true;
|
||||
return !this.z();
|
||||
}
|
||||
|
||||
public boolean x() {
|
||||
AdapterEntry var1 = this.c;
|
||||
boolean var2;
|
||||
if (var1 != null && var1.a == 100) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 != null && var1.a == 100;
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -516,11 +416,7 @@ public class VhBindArgs {
|
||||
public boolean y() {
|
||||
AdapterEntry var1 = this.c;
|
||||
boolean var2;
|
||||
if (var1 != null && var1.a == 96) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 != null && var1.a == 96;
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -528,11 +424,7 @@ public class VhBindArgs {
|
||||
public boolean z() {
|
||||
AdapterEntry var1 = this.c;
|
||||
boolean var2;
|
||||
if (var1 != null && var1.c() && this.c.c.getLocalId() == this.b.c.getLocalId()) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = var1 != null && var1.c() && this.c.c.getLocalId() == this.b.c.getLocalId();
|
||||
|
||||
return var2;
|
||||
}
|
||||
|
||||
+3
-3
@@ -46,7 +46,7 @@ public final class MsgPartCallHolder extends MsgPartHolderBase<AttachCall> {
|
||||
this.G = new StringBuilder();
|
||||
}
|
||||
|
||||
private final void a(Msg var1) {
|
||||
private void a(Msg var1) {
|
||||
this.G.setLength(0);
|
||||
MsgTimeFormatter var2 = this.F;
|
||||
Context var3 = this.C;
|
||||
@@ -55,7 +55,7 @@ public final class MsgPartCallHolder extends MsgPartHolderBase<AttachCall> {
|
||||
this.H.setTimeText(this.G);
|
||||
}
|
||||
|
||||
private final void a(boolean var1) {
|
||||
private void a(boolean var1) {
|
||||
MsgPartIconTwoRowView var2 = this.H;
|
||||
int var3;
|
||||
if (var1) {
|
||||
@@ -67,7 +67,7 @@ public final class MsgPartCallHolder extends MsgPartHolderBase<AttachCall> {
|
||||
var2.setIcon(var3);
|
||||
}
|
||||
|
||||
private final void a(boolean var1, AttachCall var2) {
|
||||
private void a(boolean var1, AttachCall var2) {
|
||||
boolean var3 = !var1;
|
||||
if (var2.h() == CallState.ERROR) {
|
||||
this.H.setSubtitleText(m.vkim_msg_list_call_error);
|
||||
|
||||
+74
-120
@@ -56,46 +56,6 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
private static final int[][] j0;
|
||||
private static final int[][] k0;
|
||||
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 {
|
||||
int[] var0 = new int[]{0, 0, 0, 0};
|
||||
@@ -119,18 +79,59 @@ 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}};
|
||||
}
|
||||
|
||||
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) {
|
||||
super(itemView);
|
||||
Context context = itemView.getContext();
|
||||
LayoutInflater var4 = LayoutInflater.from(context);
|
||||
this.b = (FluidHorizontalLayout) itemView;
|
||||
this.c = (AvatarView) itemView.findViewById(com.vk.im.ui.h.avatar);
|
||||
this.d = (Space) itemView.findViewById(com.vk.im.ui.h.avatar_space);
|
||||
this.e = (MsgBubbleView) itemView.findViewById(com.vk.im.ui.h.bubble);
|
||||
this.f = (MsgStatusView) itemView.findViewById(com.vk.im.ui.h.status);
|
||||
this.g = (ImageView) itemView.findViewById(com.vk.im.ui.h.vkim_channel_share);
|
||||
this.h = (Space) itemView.findViewById(com.vk.im.ui.h.status_space);
|
||||
this.P = (BombView) itemView.findViewById(com.vk.im.ui.h.bomb);
|
||||
this.c = itemView.findViewById(com.vk.im.ui.h.avatar);
|
||||
this.d = itemView.findViewById(com.vk.im.ui.h.avatar_space);
|
||||
this.e = itemView.findViewById(com.vk.im.ui.h.bubble);
|
||||
this.f = itemView.findViewById(com.vk.im.ui.h.status);
|
||||
this.g = itemView.findViewById(com.vk.im.ui.h.vkim_channel_share);
|
||||
this.h = itemView.findViewById(com.vk.im.ui.h.status_space);
|
||||
this.P = itemView.findViewById(com.vk.im.ui.h.bomb);
|
||||
this.B = vhBase;
|
||||
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);
|
||||
@@ -203,6 +204,10 @@ 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) {
|
||||
int var4;
|
||||
if (var3) {
|
||||
@@ -283,20 +288,15 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
case 103:
|
||||
return VhMsg.Style.EMPTY;
|
||||
default:
|
||||
StringBuilder var3 = new StringBuilder();
|
||||
var3.append("Unknown viewType: ");
|
||||
var3.append(var1);
|
||||
throw new IllegalArgumentException(var3.toString());
|
||||
String var3 = "Unknown viewType: " +
|
||||
var1;
|
||||
throw new IllegalArgumentException(var3);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
Style var3 = this.a(args.b);
|
||||
boolean var4 = args.b.f();
|
||||
@@ -411,11 +411,7 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
Msg var10 = var5.c;
|
||||
var9 = var6;
|
||||
if (var10 != null) {
|
||||
if (var10.v1() == args.g.t1()) {
|
||||
var9 = true;
|
||||
} else {
|
||||
var9 = false;
|
||||
}
|
||||
var9 = var10.v1() == args.g.t1();
|
||||
|
||||
if (var10.O1()) {
|
||||
int var12 = var10.d().ordinal();
|
||||
@@ -433,11 +429,7 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
b = args.I();
|
||||
}
|
||||
} else {
|
||||
if (var10.C1() <= args.i) {
|
||||
var6 = true;
|
||||
} else {
|
||||
var6 = false;
|
||||
}
|
||||
var6 = var10.C1() <= args.i;
|
||||
|
||||
if (!var6 && !var9) {
|
||||
var11 = MsgStatus.UNREAD;
|
||||
@@ -575,18 +567,14 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
partArgs.o = args.n;
|
||||
partArgs.s = args.v();
|
||||
partArgs.t = args.q;
|
||||
partArgs.u = var4.b() ^ true;
|
||||
partArgs.u = !var4.b();
|
||||
boolean var5;
|
||||
if (var3.i > 0) {
|
||||
var5 = true;
|
||||
} else {
|
||||
var5 = false;
|
||||
}
|
||||
var5 = var3.i > 0;
|
||||
|
||||
partArgs.v = var5;
|
||||
partArgs.w = args.k;
|
||||
partArgs.x = args.l;
|
||||
partArgs.y = this.Z ^ true;
|
||||
partArgs.y = !this.Z;
|
||||
partArgs.z = args.s;
|
||||
partArgs.A = args.t;
|
||||
partArgs.l = this.b0;
|
||||
@@ -671,7 +659,7 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
private void f(VhBindArgs args) {
|
||||
Msg var2 = args.b.c;
|
||||
if (var2 != null) {
|
||||
this.P.setStateListener((BombView.d) null);
|
||||
this.P.setStateListener(null);
|
||||
if (var2.M1() && !var2.E1()) {
|
||||
this.P.setVisibility(View.GONE);
|
||||
} else {
|
||||
@@ -810,24 +798,12 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
this.e.setFwdPadding(this.D);
|
||||
this.e.setContentPadding(this.E);
|
||||
boolean var7;
|
||||
if (args.b.a == 83) {
|
||||
var7 = true;
|
||||
} else {
|
||||
var7 = false;
|
||||
}
|
||||
var7 = args.b.a == 83;
|
||||
|
||||
boolean var5;
|
||||
if (args.a.a == 83) {
|
||||
var5 = true;
|
||||
} else {
|
||||
var5 = false;
|
||||
}
|
||||
var5 = args.a.a == 83;
|
||||
|
||||
if (!args.F() || !var7 && !var5) {
|
||||
var5 = true;
|
||||
} else {
|
||||
var5 = false;
|
||||
}
|
||||
var5 = !args.F() || !var7 && !var5;
|
||||
|
||||
MsgBubbleView var8 = this.e;
|
||||
boolean var6 = var4;
|
||||
@@ -904,18 +880,10 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
return false;
|
||||
} else {
|
||||
boolean var5;
|
||||
if (var2.a == 50) {
|
||||
var5 = true;
|
||||
} else {
|
||||
var5 = false;
|
||||
}
|
||||
var5 = var2.a == 50;
|
||||
|
||||
boolean var6;
|
||||
if (!args.z() && var2.i == 0) {
|
||||
var6 = true;
|
||||
} else {
|
||||
var6 = false;
|
||||
}
|
||||
var6 = !args.z() && var2.i == 0;
|
||||
|
||||
if (var5 || var6 || args.y() || args.x()) {
|
||||
var4 = true;
|
||||
@@ -934,11 +902,7 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
|
||||
private boolean u(int var1) {
|
||||
boolean var2;
|
||||
if (var1 != 2 && var1 != 3) {
|
||||
var2 = false;
|
||||
} else {
|
||||
var2 = true;
|
||||
}
|
||||
var2 = var1 == 2 || var1 == 3;
|
||||
|
||||
return var2;
|
||||
}
|
||||
@@ -960,9 +924,7 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
Msg var1 = this.d0;
|
||||
if (var1 != null) {
|
||||
Dialog var2 = this.e0;
|
||||
if (var2 != null && MsgPermissionHelper.b.a(var2, var1)) {
|
||||
return true;
|
||||
}
|
||||
return var2 != null && MsgPermissionHelper.b.a(var2, var1);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -997,11 +959,7 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
|
||||
public void a(VhBindArgs args) {
|
||||
boolean var2;
|
||||
if (VKThemeHelper.l() == VKTheme.VKAPP_LIGHT) {
|
||||
var2 = true;
|
||||
} else {
|
||||
var2 = false;
|
||||
}
|
||||
var2 = VKThemeHelper.l() == VKTheme.VKAPP_LIGHT;
|
||||
|
||||
this.Z = var2;
|
||||
AdapterEntry var3 = args.b;
|
||||
@@ -1062,11 +1020,7 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
|
||||
public boolean f0() {
|
||||
boolean var1;
|
||||
if (this.f0 == 100) {
|
||||
var1 = true;
|
||||
} else {
|
||||
var1 = false;
|
||||
}
|
||||
var1 = this.f0 == 100;
|
||||
|
||||
return var1;
|
||||
}
|
||||
@@ -1083,7 +1037,7 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
this.B.c(var1);
|
||||
}
|
||||
|
||||
private static enum Style {
|
||||
private enum Style {
|
||||
BUTTON(6),
|
||||
EMPTY(7),
|
||||
FWD_SENDER(4),
|
||||
@@ -1095,14 +1049,14 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
|
||||
public final int index;
|
||||
|
||||
private Style(int var3) {
|
||||
Style(int var3) {
|
||||
this.index = var3;
|
||||
}
|
||||
}
|
||||
|
||||
private class h implements Functions<Unit> {
|
||||
private int a;
|
||||
private Runnable b;
|
||||
private final int a;
|
||||
private final Runnable b;
|
||||
|
||||
private h() {
|
||||
this.a = Screen.a(12);
|
||||
|
||||
@@ -26,30 +26,23 @@ import com.vtosters.lite.R;
|
||||
|
||||
public final class MentionsController {
|
||||
private final RichEditText a;
|
||||
|
||||
private final ImEngine mImEngine;
|
||||
private final View j;
|
||||
private final b k;
|
||||
private boolean state;
|
||||
private CoordinatorLayout mCoordinatorLayout;
|
||||
private VkBottomSheetBehavior<RecyclerView> mBottomSheetBehavior;
|
||||
private boolean e;
|
||||
private DialogMentionComponent mDialogMentionComponent;
|
||||
private MentionsManager mMentionsManager;
|
||||
private final ImEngine mImEngine;
|
||||
private int i;
|
||||
private final View j;
|
||||
private final b k;
|
||||
|
||||
public interface b {
|
||||
boolean c();
|
||||
|
||||
boolean d();
|
||||
}
|
||||
private final DialogMentionComponent mDialogMentionComponent;
|
||||
private final MentionsManager mMentionsManager;
|
||||
private final int i;
|
||||
|
||||
public MentionsController(ImEngine imEngine, int i, View view, b bVar) {
|
||||
this.mImEngine = imEngine;
|
||||
this.i = i;
|
||||
this.j = view;
|
||||
this.k = bVar;
|
||||
this.a = (RichEditText) this.j.findViewById(R.id.writebar_edit);
|
||||
this.a = this.j.findViewById(R.id.writebar_edit);
|
||||
this.mMentionsManager = new MentionsManager(this.a, new MentionSuggestionsSupplier() {
|
||||
|
||||
@Override
|
||||
@@ -71,7 +64,7 @@ public final class MentionsController {
|
||||
|
||||
@Override
|
||||
public void b() {
|
||||
MentionsController.this.mDialogMentionComponent.a(0, (String) null);
|
||||
MentionsController.this.mDialogMentionComponent.a(0, null);
|
||||
MentionsController.this.g();
|
||||
}
|
||||
});
|
||||
@@ -92,18 +85,18 @@ public final class MentionsController {
|
||||
});
|
||||
}
|
||||
|
||||
public final void g() {
|
||||
public void g() {
|
||||
this.e = false;
|
||||
j();
|
||||
}
|
||||
|
||||
private final void h() {
|
||||
private void h() {
|
||||
if (this.state) {
|
||||
return;
|
||||
}
|
||||
View inflate = ((ViewStub) this.j.findViewById(R.id.mentions_container_stub)).inflate();
|
||||
ViewGroup viewGroup = (ViewGroup) inflate.findViewById(R.id.mentions_container);
|
||||
viewGroup.addView(this.mDialogMentionComponent.a(viewGroup, (Bundle) null));
|
||||
ViewGroup viewGroup = inflate.findViewById(R.id.mentions_container);
|
||||
viewGroup.addView(this.mDialogMentionComponent.a(viewGroup, null));
|
||||
this.mCoordinatorLayout = inflate.findViewById(R.id.mentions_cl);
|
||||
this.mBottomSheetBehavior = (VkBottomSheetBehavior<RecyclerView>) ((CoordinatorLayout.LayoutParams) viewGroup.getLayoutParams()).getBehavior();
|
||||
this.mBottomSheetBehavior.a(new VkBottomSheetBehavior.b() {
|
||||
@@ -120,12 +113,12 @@ public final class MentionsController {
|
||||
this.state = true;
|
||||
}
|
||||
|
||||
public final void i() {
|
||||
public void i() {
|
||||
this.e = true;
|
||||
j();
|
||||
}
|
||||
|
||||
public final void j() {
|
||||
public void j() {
|
||||
if (this.k.d()) {
|
||||
Context context = this.j.getContext();
|
||||
Activity f = ContextExtKt.f(context);
|
||||
@@ -139,27 +132,33 @@ public final class MentionsController {
|
||||
}
|
||||
}
|
||||
|
||||
public final void a() {
|
||||
public void a() {
|
||||
this.mDialogMentionComponent.g();
|
||||
}
|
||||
|
||||
public final void b() {
|
||||
public void b() {
|
||||
this.mDialogMentionComponent.h();
|
||||
}
|
||||
|
||||
public final b c() {
|
||||
public b c() {
|
||||
return this.k;
|
||||
}
|
||||
|
||||
public final int d() {
|
||||
public int d() {
|
||||
return this.i;
|
||||
}
|
||||
|
||||
public final void e() {
|
||||
public void e() {
|
||||
this.mDialogMentionComponent.q();
|
||||
}
|
||||
|
||||
public final void f() {
|
||||
public void f() {
|
||||
this.mDialogMentionComponent.r();
|
||||
}
|
||||
|
||||
public interface b {
|
||||
boolean c();
|
||||
|
||||
boolean d();
|
||||
}
|
||||
}
|
||||
@@ -12,15 +12,15 @@ import android.view.ViewGroup;
|
||||
import com.vk.im.ui.o;
|
||||
|
||||
public class StoryBorderView extends View {
|
||||
private boolean B;
|
||||
private final Paint a;
|
||||
private final int g;
|
||||
private final int h;
|
||||
private boolean B;
|
||||
private LinearGradient f15747b;
|
||||
private int f15748c;
|
||||
private int f15749d;
|
||||
private int f15750e;
|
||||
private int f15751f;
|
||||
private final int g;
|
||||
private final int h;
|
||||
|
||||
public StoryBorderView(Context context) {
|
||||
this(context, null, 0, 6);
|
||||
@@ -34,10 +34,32 @@ public class StoryBorderView extends View {
|
||||
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() {
|
||||
return this.f15749d;
|
||||
}
|
||||
|
||||
public void setBorderColor(int i) {
|
||||
if (this.f15749d != i) {
|
||||
this.f15749d = i;
|
||||
this.a.setColor(i);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public int getBorderGradientEndColor() {
|
||||
return this.h;
|
||||
}
|
||||
@@ -50,14 +72,33 @@ public class StoryBorderView extends View {
|
||||
return this.f15750e;
|
||||
}
|
||||
|
||||
public void setBorderWidth(int i) {
|
||||
if (this.f15750e != i) {
|
||||
this.f15750e = i;
|
||||
this.a.setStrokeWidth(i);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public int getPadding() {
|
||||
return this.f15751f;
|
||||
}
|
||||
|
||||
public void setPadding(int i) {
|
||||
if (this.f15751f != i) {
|
||||
this.f15751f = i;
|
||||
setPadding(i, i, i, i);
|
||||
}
|
||||
}
|
||||
|
||||
public int getViewSize() {
|
||||
return this.f15748c;
|
||||
}
|
||||
|
||||
public void setViewSize(int i) {
|
||||
this.f15748c = i;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
canvas.drawOval(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom(), this.a);
|
||||
@@ -69,22 +110,6 @@ public class StoryBorderView extends View {
|
||||
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
|
||||
public void setLayoutParams(ViewGroup.LayoutParams layoutParams) {
|
||||
super.setLayoutParams(layoutParams);
|
||||
@@ -108,29 +133,4 @@ public class StoryBorderView extends View {
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -23,8 +23,8 @@ import com.vtosters.lite.R;
|
||||
import com.vtosters.lite.ViewUtils;
|
||||
import com.vtosters.lite.ui.MusicErrorViewHelper;
|
||||
import com.vtosters.lite.ui.holder.RecyclerHolder;
|
||||
import ru.vtosters.lite.music.Genius;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.music.Genius;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -156,7 +156,7 @@ public class LyricsHolder extends RecyclerHolder<PlayerInfo> implements View.OnC
|
||||
|
||||
@Override // com.vk.api.base.ApiCallback
|
||||
public void a(VKApiExecutionException vKApiExecutionException) {
|
||||
if (Preferences.getBoolValue("useGenius", false)) {
|
||||
if (Preferences.getBoolValue("useGenius", false) && !Preferences.serverFeaturesDisable()) {
|
||||
var text = Genius.getTextMusic(a);
|
||||
var lyrics = new AudioGetLyrics.a();
|
||||
lyrics.a = text;
|
||||
|
||||
@@ -36,37 +36,37 @@ public final class CommunityBorderedImageView extends BorderedCircleImageView im
|
||||
|
||||
public CommunityBorderedImageView(Context context, AttributeSet attributeSet, int i) {
|
||||
super(context, attributeSet, i);
|
||||
this.g0 = VKThemeHelper.d((int) R.attr.accent);
|
||||
this.h0 = ContextExtKt.a(context, (int) R.color.gray_200);
|
||||
this.g0 = VKThemeHelper.d(R.attr.accent);
|
||||
this.h0 = ContextExtKt.a(context, R.color.gray_200);
|
||||
this.i0 = new PorterDuffColorFilter(this.g0, PorterDuff.Mode.SRC_IN);
|
||||
this.j0 = new PorterDuffColorFilter(this.h0, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
|
||||
public final void c(int unread, int read) { // get unread and read resid
|
||||
public void c(int unread, int read) { // get unread and read resid
|
||||
this.unread = unread;
|
||||
this.read = read;
|
||||
this.T = BitmapFactory.decodeResource(getResources(), this.unread);
|
||||
}
|
||||
|
||||
public final int getPrimaryColor() {
|
||||
public int getPrimaryColor() {
|
||||
return this.g0;
|
||||
}
|
||||
|
||||
public final void setPrimaryColor(int i) {
|
||||
public void setPrimaryColor(int i) {
|
||||
this.g0 = i;
|
||||
this.i0 = new PorterDuffColorFilter(i, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
|
||||
public final int getWasViewedColor() {
|
||||
public int getWasViewedColor() {
|
||||
return this.h0;
|
||||
}
|
||||
|
||||
public final void setWasViewedColor(int i) {
|
||||
public void setWasViewedColor(int i) {
|
||||
this.h0 = i;
|
||||
this.j0 = new PorterDuffColorFilter(i, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
|
||||
public final void o() {
|
||||
public void o() {
|
||||
this.f0 = false;
|
||||
l();
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public final class CommunityBorderedImageView extends BorderedCircleImageView im
|
||||
}
|
||||
}
|
||||
|
||||
public final void setStoryContainer(StoriesContainer storiesContainer) {
|
||||
public void setStoryContainer(StoriesContainer storiesContainer) {
|
||||
if (storiesContainer.L1()) {
|
||||
this.f0 = true;
|
||||
m();
|
||||
|
||||
@@ -30,14 +30,14 @@ public class TargetImageView extends VKMultiImageView {
|
||||
private static final int I = Screen.a(2);
|
||||
private final int B;
|
||||
private final int C;
|
||||
private final RectF f21629d;
|
||||
private final Paint f21630e;
|
||||
private final RectF g;
|
||||
private final Paint h;
|
||||
private Drawable D;
|
||||
private String[] F;
|
||||
private int G;
|
||||
private final RectF f21629d;
|
||||
private final Paint f21630e;
|
||||
private Canvas f21631f;
|
||||
private final RectF g;
|
||||
private final Paint h;
|
||||
|
||||
public TargetImageView(Context context, Drawable d) {
|
||||
this(context, null, 0, 6);
|
||||
@@ -51,6 +51,43 @@ public class TargetImageView extends VKMultiImageView {
|
||||
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() {
|
||||
int i = this.G;
|
||||
for (int i2 = 0; i2 < i; i2++) {
|
||||
@@ -251,41 +288,4 @@ public class TargetImageView extends VKMultiImageView {
|
||||
drawable.setBounds(i - drawable.getIntrinsicWidth(), i2 - this.D.getIntrinsicHeight(), i, i2);
|
||||
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,6 +104,25 @@ 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 VKImageView mImageBg;
|
||||
private final VKImageView mPackImage;
|
||||
@@ -149,23 +168,4 @@ public final class StickerDetailsAdapter extends RecyclerView.Adapter<RecyclerVi
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -382,7 +382,7 @@ public class StoryCircleImageView extends BorderedCircleImageView implements The
|
||||
return;
|
||||
}
|
||||
|
||||
pipelineDraweeControllerBuilder.a((Supplier<DataSource<CloseableReference<CloseableImage>>>) () -> StoryCircleImageView.this.a(list));
|
||||
pipelineDraweeControllerBuilder.a(() -> StoryCircleImageView.this.a(list));
|
||||
return;
|
||||
}
|
||||
pipelineDraweeControllerBuilder.b(null);
|
||||
|
||||
@@ -19664,6 +19664,35 @@ public final class R {
|
||||
public static final int invalidate_theme_cache_each_update_title = 0x7f121890; // 2131892368
|
||||
public static final int invertFilters = 0x7f121891; // 2131892369
|
||||
public static final int invertFilters_summ = 0x7f121892; // 2131892370
|
||||
public static final int invertcached_summ = 0x7f121893; // 2131892371
|
||||
public static final int invertcached_title = 0x7f121894; // 2131892372
|
||||
public static final int microg_dialog1 = 0x7f121895; // 2131892373
|
||||
public static final int microg_dialog2 = 0x7f121896; // 2131892374
|
||||
public static final int microg_dialog3 = 0x7f121897; // 2131892375
|
||||
public static final int serverFeaturesDisable = 0x7f121898; // 2131892376
|
||||
public static final int serverFeaturesDisable_summ = 0x7f121899; // 2131892377
|
||||
public static final int sett_autoupdates = 0x7f12189a; // 2131892378
|
||||
public static final int sett_autoupdates_summ = 0x7f12189b; // 2131892379
|
||||
public static final int sett_battery = 0x7f12189c; // 2131892380
|
||||
public static final int sett_battery_summ1 = 0x7f12189d; // 2131892381
|
||||
public static final int sett_battery_summ2 = 0x7f12189e; // 2131892382
|
||||
public static final int sett_chats = 0x7f12189f; // 2131892383
|
||||
public static final int sett_chats_summ = 0x7f1218a0; // 2131892384
|
||||
public static final int sett_community = 0x7f1218a1; // 2131892385
|
||||
public static final int sett_community_summ = 0x7f1218a2; // 2131892386
|
||||
public static final int sett_missing_links = 0x7f1218a3; // 2131892387
|
||||
public static final int sett_missing_links_summ = 0x7f1218a4; // 2131892388
|
||||
public static final int sett_nogms_summ = 0x7f1218a5; // 2131892389
|
||||
public static final int sett_notifs = 0x7f1218a6; // 2131892390
|
||||
public static final int sett_notifs_summ = 0x7f1218a7; // 2131892391
|
||||
public static final int sett_recommendations = 0x7f1218a8; // 2131892392
|
||||
public static final int tgs_token_missing = 0x7f1218aa; // 2131892394
|
||||
public static final int tgs_token_reset = 0x7f1218ab; // 2131892395
|
||||
public static final int tgs_token_reset_dialog = 0x7f1218ac; // 2131892396
|
||||
public static final int tgs_token_reset_menu = 0x7f1218ad; // 2131892397
|
||||
public static final int update_err = 0x7f1218ae; // 2131892398
|
||||
public static final int update_latest = 0x7f1218af; // 2131892399
|
||||
public static final int APKTOOL_DUMMY_18a9 = 0x7f1218a9; // 2131892393
|
||||
}
|
||||
|
||||
public static final class style {
|
||||
|
||||
+8
-8
@@ -35,16 +35,16 @@ public class BottomNavigationItemView extends FrameLayout implements MenuView.It
|
||||
private final View mCounterContainer;
|
||||
private final TextView mCounter;
|
||||
private final View mDot;
|
||||
private final int mMargin;
|
||||
private final float mSmallScale;
|
||||
private final ImageView mIcon;
|
||||
private final ImageView mActionIcon;
|
||||
private int mItemPos;
|
||||
private MenuItemImpl mItemData;
|
||||
private ColorStateList mColorStateList;
|
||||
private final int mMargin;
|
||||
private final float mSmallScale;
|
||||
private boolean mShiftingModeEnabled;
|
||||
private boolean mIconsModeEnabled;
|
||||
private boolean mStaticModeEnabled;
|
||||
private final ImageView mIcon;
|
||||
private final ImageView mActionIcon;
|
||||
|
||||
public BottomNavigationItemView(@NonNull Context context) {
|
||||
this(context, null);
|
||||
@@ -101,6 +101,10 @@ public class BottomNavigationItemView extends FrameLayout implements MenuView.It
|
||||
return this.mItemPos;
|
||||
}
|
||||
|
||||
public void setItemPosition(int pos) {
|
||||
this.mItemPos = pos;
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
public void initialize(MenuItemImpl impl, int i) {
|
||||
this.mItemData = impl;
|
||||
@@ -310,10 +314,6 @@ public class BottomNavigationItemView extends FrameLayout implements MenuView.It
|
||||
ViewCompat.setBackground(this, resId != 0 ? ContextCompat.getDrawable(this.getContext(), resId) : null);
|
||||
}
|
||||
|
||||
public void setItemPosition(int pos) {
|
||||
this.mItemPos = pos;
|
||||
}
|
||||
|
||||
public void setShiftingMode(boolean var1) {
|
||||
this.mShiftingModeEnabled = var1;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package ru.vtosters.hooks;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.utils.NewsFeedFiltersUtils;
|
||||
import ru.vtosters.lite.utils.newsfeed.NewsFeedFiltersUtils;
|
||||
|
||||
public class AdBlockHook {
|
||||
public static JSONObject discoverInject(JSONObject json) throws JSONException {
|
||||
@@ -11,11 +11,15 @@ public class AdBlockHook {
|
||||
}
|
||||
|
||||
public static JSONArray feedInject(JSONArray items) {
|
||||
return NewsFeedFiltersUtils.feedInject(items);
|
||||
return NewsFeedFiltersUtils.feedInject(items, false);
|
||||
|
||||
}
|
||||
|
||||
public static JSONObject storiesads(JSONObject json, boolean isDeleteFix) throws JSONException {
|
||||
return NewsFeedFiltersUtils.storiesads(json, isDeleteFix);
|
||||
public static JSONArray wallGetById(JSONArray items) {
|
||||
return NewsFeedFiltersUtils.feedInject(items, true);
|
||||
}
|
||||
|
||||
public static JSONObject storiesads(JSONObject json, boolean isDeleteFix) {
|
||||
return NewsFeedFiltersUtils.storiesAds(json, isDeleteFix);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package ru.vtosters.hooks;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.music.catalog.inject.CatalogJsonInjector;
|
||||
import ru.vtosters.hooks.music.injectors.CatalogJsonInjector;
|
||||
|
||||
public class CatalogsHook {
|
||||
public static JSONObject injectCatalogGetAudio(JSONObject json) {
|
||||
|
||||
@@ -6,11 +6,12 @@ import android.content.Context;
|
||||
import android.os.Build;
|
||||
import com.google.firebase.iid.FirebaseInstanceIdReceiver;
|
||||
import com.google.firebase.iid.FirebaseInstanceIdReceiver2;
|
||||
import com.google.firebase.iid.FirebaseInstanceIdReceiver3;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class GmsHook {
|
||||
private static final boolean needToSpoof = !isGmsInstalled() && isFakeGmsInstalled();
|
||||
private static final boolean needToSpoof = !isGmsInstalled() && (isFakeGmsInstalled() || isFakeGms2Installed());
|
||||
|
||||
public static boolean isGmsInstalled() {
|
||||
try {
|
||||
@@ -30,8 +31,17 @@ public class GmsHook {
|
||||
}
|
||||
} // Microg Google Market Services check
|
||||
|
||||
public static boolean isFakeGms2Installed() {
|
||||
try {
|
||||
AndroidUtils.getGlobalContext().getPackageManager().getPackageInfo("app.revanced.android.gms", 0);
|
||||
return true;
|
||||
} catch (Exception unused) {
|
||||
return false;
|
||||
}
|
||||
} // Microg Google Market Services check
|
||||
|
||||
public static boolean isAnyServicesInstalled() {
|
||||
return isGmsInstalled() || isFakeGmsInstalled();
|
||||
return isGmsInstalled() || isFakeGmsInstalled() || isFakeGms2Installed();
|
||||
}
|
||||
|
||||
public static void fixGapps() {
|
||||
@@ -45,7 +55,7 @@ public class GmsHook {
|
||||
} // Music channels fix
|
||||
|
||||
public static String replaceGMSPackage(String str) {
|
||||
return needToSpoof ? str.replaceAll("com.google", "com.mgoogle") : str;
|
||||
return needToSpoof ? str.replaceAll("com.google", (isFakeGms2Installed() ? "app.revanced" : "com.mgoogle")) : str;
|
||||
}
|
||||
|
||||
public static String getFirebaseInstanceIdReceiver() {
|
||||
@@ -53,6 +63,6 @@ public class GmsHook {
|
||||
}
|
||||
|
||||
public static Class getFirebaseInstanceIdReceiverClass() {
|
||||
return needToSpoof ? FirebaseInstanceIdReceiver2.class : FirebaseInstanceIdReceiver.class;
|
||||
return needToSpoof ? (isFakeGms2Installed() ? FirebaseInstanceIdReceiver3.class : FirebaseInstanceIdReceiver2.class) : FirebaseInstanceIdReceiver.class;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,11 @@ package ru.vtosters.hooks;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.utils.FriendsCatalogUtils;
|
||||
import ru.vtosters.lite.utils.NewsFeedFiltersUtils;
|
||||
import ru.vtosters.lite.utils.OnlineBypass;
|
||||
import ru.vtosters.lite.utils.SuperAppUtils;
|
||||
import ru.vtosters.lite.utils.newsfeed.NewsFeedFiltersUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
@@ -30,10 +31,10 @@ public class JsonInjectors {
|
||||
}
|
||||
|
||||
public static JSONArray newsfeedlist(JSONArray items) throws JSONException {
|
||||
return NewsFeedFiltersUtils.newsfeedlist(items);
|
||||
return Preferences.getBoolValue("unlockCustomLists", false) ? NewsFeedFiltersUtils.setNewsfeedLists(items) : items;
|
||||
}
|
||||
|
||||
public static JSONObject friends(JSONObject json) throws JSONException, ParseException, IOException {
|
||||
return FriendsCatalogUtils.inject(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import ru.vtosters.lite.concurrent.VTExecutors;
|
||||
import ru.vtosters.lite.downloaders.notifications.NotificationChannels;
|
||||
import ru.vtosters.lite.ssfs.UsersList;
|
||||
import ru.vtosters.lite.themes.ThemesManager;
|
||||
import ru.vtosters.lite.ui.dialogs.DisableBattery;
|
||||
import ru.vtosters.lite.ui.dialogs.InstallGMS;
|
||||
import ru.vtosters.lite.ui.dialogs.OTADialog;
|
||||
import ru.vtosters.lite.ui.dialogs.Start;
|
||||
@@ -22,16 +21,15 @@ import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
import ru.vtosters.lite.utils.NavigatorUtils;
|
||||
import ru.vtosters.lite.utils.VTVerifications;
|
||||
import ru.vtosters.sponsorpost.utils.Updates;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.checkupdates;
|
||||
import static ru.vtosters.lite.ui.dialogs.ServerDialog.sendRequest;
|
||||
import static ru.vtosters.lite.utils.CacheUtils.getInstance;
|
||||
import static ru.vtosters.lite.utils.NewsFeedFiltersUtils.setupFilters;
|
||||
|
||||
public class MainActivityInjector {
|
||||
public static void inject(Activity activity) {
|
||||
SystemThemeChangerHook.themeOnStart(activity);
|
||||
sendRequest();
|
||||
|
||||
UsersList.getUsersList();
|
||||
VTVerifications.load(activity);
|
||||
|
||||
@@ -39,18 +37,20 @@ public class MainActivityInjector {
|
||||
|
||||
VTExecutors.getSlowTasksScheduler().a(() -> {
|
||||
getInstance().autoCleaningCache();
|
||||
}); // slowTasksScheduler
|
||||
|
||||
setupFilters();
|
||||
if (!Preferences.serverFeaturesDisable()) {
|
||||
Updates.updateFilters();
|
||||
Updates.updatePosts();
|
||||
}
|
||||
}); // slowTasksScheduler
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannels.createChannels();
|
||||
}
|
||||
|
||||
if (Preferences.isNewBuild()
|
||||
&&!ThemesUtils.isMonetTheme()
|
||||
&&ThemesManager.canApplyCustomAccent())
|
||||
{
|
||||
&& !ThemesUtils.isMonetTheme()
|
||||
&& ThemesManager.canApplyCustomAccent()) {
|
||||
Preferences.updateBuildNumber();
|
||||
updateBinsAndTmpArchive(activity);
|
||||
}
|
||||
@@ -64,7 +64,6 @@ public class MainActivityInjector {
|
||||
|
||||
Start.alert(activity);
|
||||
InstallGMS.alert(activity);
|
||||
DisableBattery.alert(activity);
|
||||
// VKIDProtection.alert(activity);
|
||||
//needs to show selected tgs pack count in settings after cold launch
|
||||
TelegramStickersService.getInstance(activity);
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.vk.api.internal.MethodCall;
|
||||
import com.vk.im.ui.providers.audiomsg.ImAudioMsgPlayerProvider;
|
||||
import com.vk.im.ui.providers.audiomsg.PlayerActionSources;
|
||||
import com.vtosters.lite.im.ImEngineProvider;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.translators.BaseTranslator;
|
||||
import ru.vtosters.lite.ui.dialogs.MessageSettings;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
@@ -20,7 +21,7 @@ import static ru.vtosters.lite.ui.dialogs.MessageSettings.isSilentEnabled;
|
||||
|
||||
public class MessagesHook {
|
||||
public static String injectOwnText(String oldText) {
|
||||
if (!autotranslate() || TextUtils.isEmpty(oldText))
|
||||
if (!autotranslate() || Preferences.serverFeaturesDisable() || TextUtils.isEmpty(oldText))
|
||||
return oldText;
|
||||
var instance = BaseTranslator.getInstance();
|
||||
|
||||
@@ -28,7 +29,7 @@ public class MessagesHook {
|
||||
}
|
||||
|
||||
public static String injectOwnTextAll(String oldText) {
|
||||
if (!autoalltranslate() || TextUtils.isEmpty(oldText)) {
|
||||
if (!autoalltranslate() || Preferences.serverFeaturesDisable() || TextUtils.isEmpty(oldText)) {
|
||||
return oldText;
|
||||
}
|
||||
var instance = BaseTranslator.getInstance();
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
|
||||
import ru.vtosters.lite.music.cache.FileCacheImplementation;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class MusicCacheFilesHook {
|
||||
public static File getTrackFile(String trackId) {
|
||||
return new File(FileCacheImplementation.getTrackFolder(trackId), "track.mp3");
|
||||
}
|
||||
|
||||
public static boolean isTrackExist(String trackId) {
|
||||
return CacheDatabaseDelegate.isCached(trackId);
|
||||
}
|
||||
}
|
||||
@@ -2,17 +2,25 @@ package ru.vtosters.hooks;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.PowerManager;
|
||||
import android.util.Log;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.vk.core.preference.Preference;
|
||||
import com.vk.discover.DiscoverItemDecorator;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.concurrent.VTExecutors;
|
||||
import ru.vtosters.lite.utils.NetworkUtils;
|
||||
import ru.vtosters.sponsorpost.services.PostService;
|
||||
import ru.vtosters.sponsorpost.utils.PostsPreferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import static java.lang.Long.MAX_VALUE;
|
||||
import static ru.vtosters.hooks.other.Preferences.*;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
|
||||
|
||||
public class NewsfeedHook {
|
||||
public static long getUpdateNewsfeed(boolean refresh_timeout) {
|
||||
@@ -22,8 +30,7 @@ public class NewsfeedHook {
|
||||
return switch (getString("newsupdate")) {
|
||||
case "no_update" -> MAX_VALUE;
|
||||
case "imd_update" -> 10000L;
|
||||
default ->
|
||||
Preference.b().getLong(refresh_timeout ? "refresh_timeout_top" : "refresh_timeout_recent", 600000L);
|
||||
default -> Preference.b().getLong(refresh_timeout ? "refresh_timeout_top" : "refresh_timeout_recent", 600000L);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -53,41 +60,70 @@ public class NewsfeedHook {
|
||||
}
|
||||
|
||||
public static String[] feedParams() {
|
||||
HashSet<String> params = new HashSet<>();
|
||||
params.add("post");
|
||||
params.add("photo");
|
||||
params.add("photo_tag");
|
||||
List<String> params = List.of("post", "photo", "photo_tag", "friends_recomm", "app_widget", "promo_button", "authors_rec");
|
||||
|
||||
if (!friendsrecomm()) {
|
||||
params.add("friends_recomm");
|
||||
HashSet<String> filteredParams = new HashSet<>();
|
||||
|
||||
for (String param : params) {
|
||||
if (!isDisabled(param)) {
|
||||
filteredParams.add(param);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ads()) {
|
||||
params.add("app_widget");
|
||||
params.add("promo_button");
|
||||
}
|
||||
return filteredParams.toArray(new String[0]);
|
||||
}
|
||||
|
||||
if (!authorsrecomm()) {
|
||||
params.add("authors_rec");
|
||||
}
|
||||
|
||||
return params.toArray(new String[0]);
|
||||
private static boolean isDisabled(String param) {
|
||||
return switch (param) {
|
||||
case "friends_recomm" -> friendsrecomm();
|
||||
case "app_widget", "promo_button" -> ads();
|
||||
case "authors_rec" -> authorsrecomm();
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
public static void adsParams(HashSet<String> hashSet) {
|
||||
String[] adsParams = {"ads_disabled", "ads_app_slider", "ads_site_slider", "ads_app", "ads_site", "ads_post", "ads_app_video", "ads_post_pretty_cards", "ads_post_snippet_video"};
|
||||
|
||||
if (ads()) {
|
||||
hashSet.add("ads_disabled");
|
||||
hashSet.add(adsParams[0]);
|
||||
hashSet.add(adsParams[1]);
|
||||
} else {
|
||||
hashSet.add("ads_app_slider");
|
||||
hashSet.add("ads_site_slider");
|
||||
Collections.addAll(hashSet, adsParams);
|
||||
}
|
||||
|
||||
hashSet.add("ads_app");
|
||||
hashSet.add("ads_site");
|
||||
hashSet.add("ads_post");
|
||||
hashSet.add("ads_app_video");
|
||||
hashSet.add("ads_post_pretty_cards");
|
||||
hashSet.add("ads_post_snippet_video");
|
||||
if (Preferences.milkshake()) {
|
||||
hashSet.remove(adsParams[1]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void takeOwnerIdSponsorPost(int ownerid) {
|
||||
if (NetworkUtils.isNetworkConnected() && PostsPreferences.isEnabled() && !Preferences.serverFeaturesDisable()) {
|
||||
VTExecutors.getIoScheduler().a(() -> {
|
||||
List<Long> postIds = PostService.getPostIdsByOwnerId((long) ownerid, 0L);
|
||||
PostsPreferences.saveGroupSpecifiedPosts(postIds, (long) ownerid);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void takeOwnerIdPostIdSponsorPost(String[] strArr) {
|
||||
long ownerid = Long.parseLong(strArr[0].split("_")[0]);
|
||||
long postId = Long.parseLong(strArr[0].split("_")[1]);
|
||||
|
||||
if (PostsPreferences.isPostAd(ownerid, postId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NetworkUtils.isNetworkConnected() && PostsPreferences.isEnabled() && !Preferences.serverFeaturesDisable() && PostsPreferences.isGroupAd(ownerid)) {
|
||||
VTExecutors.getIoScheduler().a(() -> {
|
||||
boolean postIds = PostService.isPostAd(ownerid, postId);
|
||||
|
||||
if (postIds) {
|
||||
PostsPreferences.saveAdPostInfo(ownerid, postId);
|
||||
sendToast("Этот пост помечен как рекламный");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isPowerSaveMode() {
|
||||
|
||||
@@ -5,11 +5,9 @@ import com.vtosters.lite.R;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.*;
|
||||
import static ru.vtosters.lite.net.Request.makeRequest;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
@@ -115,14 +113,20 @@ public class OnlineFormatterHook {
|
||||
return AndroidUtils.getString(R.string.custom_online) + " " + appname;
|
||||
}
|
||||
|
||||
public static JSONObject onlineHook(JSONObject json) throws ParseException, IOException, JSONException {
|
||||
if (getBoolValue("onlinefix", false)) JsonInjectors.setOnlineInfo(json);
|
||||
public static JSONObject onlineHook(JSONObject json) {
|
||||
if (!getBoolValue("onlinefix", false) || Preferences.serverFeaturesDisable()) return json;
|
||||
|
||||
try {
|
||||
JsonInjectors.setOnlineInfo(json);
|
||||
} catch (JSONException e) {
|
||||
Log.e("onlineHook", e.getMessage());
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public static JSONArray onlineHookList(JSONArray jsonArr) throws ParseException, IOException, JSONException {
|
||||
if (!getBoolValue("onlinefix", false)) return jsonArr;
|
||||
public static JSONArray onlineHookList(JSONArray jsonArr) {
|
||||
if (!getBoolValue("onlinefix", false) || Preferences.serverFeaturesDisable()) return jsonArr;
|
||||
|
||||
try {
|
||||
JsonInjectors.setOnlineInfoUsers(jsonArr);
|
||||
@@ -134,7 +138,7 @@ public class OnlineFormatterHook {
|
||||
}
|
||||
|
||||
public static JSONObject onlineHookProfiles(JSONObject json) {
|
||||
if (!getBoolValue("onlinefix", false)) return json;
|
||||
if (!getBoolValue("onlinefix", false) || Preferences.serverFeaturesDisable()) return json;
|
||||
|
||||
try {
|
||||
JsonInjectors.setOnlineInfoUsers(json.optJSONArray("profiles"));
|
||||
@@ -146,7 +150,7 @@ public class OnlineFormatterHook {
|
||||
}
|
||||
|
||||
public static JSONObject onlineHookItems(JSONObject json) {
|
||||
if (!getBoolValue("onlinefix", false)) return json;
|
||||
if (!getBoolValue("onlinefix", false) || Preferences.serverFeaturesDisable()) return json;
|
||||
|
||||
try {
|
||||
JsonInjectors.setOnlineInfoUsers(json.optJSONArray("items"));
|
||||
@@ -157,8 +161,8 @@ public class OnlineFormatterHook {
|
||||
return json;
|
||||
}
|
||||
|
||||
public static JSONObject onlineHookRequestsAndRecommendations(JSONObject json) throws ParseException, IOException, JSONException {
|
||||
if (!getBoolValue("onlinefix", false)) return json;
|
||||
public static JSONObject onlineHookRequestsAndRecommendations(JSONObject json) {
|
||||
if (!getBoolValue("onlinefix", false) || Preferences.serverFeaturesDisable()) return json;
|
||||
|
||||
try {
|
||||
JsonInjectors.setOnlineInfoUsers(json.optJSONObject("read_requests").optJSONArray("items"));
|
||||
|
||||
@@ -108,22 +108,22 @@ public class ProxyHook {
|
||||
|
||||
RadioButton rgDefault = new RadioButton(new ContextThemeWrapper(ctx, com.vtosters.lite.R.style.Widget_AppCompat_CompoundButton_RadioButton));
|
||||
RadioButton rgZaborona = new RadioButton(new ContextThemeWrapper(ctx, com.vtosters.lite.R.style.Widget_AppCompat_CompoundButton_RadioButton));
|
||||
RadioButton rgRandomProxy = new RadioButton(new ContextThemeWrapper(ctx, com.vtosters.lite.R.style.Widget_AppCompat_CompoundButton_RadioButton));
|
||||
// RadioButton rgRandomProxy = new RadioButton(new ContextThemeWrapper(ctx, com.vtosters.lite.R.style.Widget_AppCompat_CompoundButton_RadioButton));
|
||||
RadioButton rgVika = new RadioButton(new ContextThemeWrapper(ctx, com.vtosters.lite.R.style.Widget_AppCompat_CompoundButton_RadioButton));
|
||||
|
||||
SwitchHook.setCompoundButton(rgDefault);
|
||||
SwitchHook.setCompoundButton(rgZaborona);
|
||||
SwitchHook.setCompoundButton(rgRandomProxy);
|
||||
// SwitchHook.setCompoundButton(rgRandomProxy);
|
||||
SwitchHook.setCompoundButton(rgVika);
|
||||
|
||||
rg.addView(rgDefault);
|
||||
rg.addView(rgVika);
|
||||
rg.addView(rgZaborona);
|
||||
rg.addView(rgRandomProxy);
|
||||
// rg.addView(rgRandomProxy);
|
||||
|
||||
rgDefault.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
|
||||
rgZaborona.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
|
||||
rgRandomProxy.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
|
||||
// rgRandomProxy.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
|
||||
rgVika.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
|
||||
|
||||
rg.setPadding(dp2px(18f), dp2px(12f), dp2px(18f), 0);
|
||||
@@ -134,15 +134,15 @@ public class ProxyHook {
|
||||
rgZaborona.setText(ctx.getString(R.string.proxy_enable) + " (Zaborona)");
|
||||
rgZaborona.setTextColor(getTextAttr());
|
||||
|
||||
rgRandomProxy.setText(ctx.getString(R.string.proxy_enable) + " (Random Socks Proxy)");
|
||||
rgRandomProxy.setTextColor(getTextAttr());
|
||||
// rgRandomProxy.setText(ctx.getString(R.string.proxy_enable) + " (Random Socks Proxy)");
|
||||
// rgRandomProxy.setTextColor(getTextAttr());
|
||||
|
||||
rgVika.setText(ctx.getString(R.string.proxy_enable) + " (Vika Mobile)");
|
||||
rgVika.setTextColor(getTextAttr());
|
||||
|
||||
rgZaborona.setChecked(isZaboronaEnabled());
|
||||
rgDefault.setChecked(!isZaboronaEnabled() && !isRandomProxyEnabled() && !isVikaProxyEnabled());
|
||||
rgRandomProxy.setChecked(isRandomProxyEnabled());
|
||||
// rgRandomProxy.setChecked(isRandomProxyEnabled());
|
||||
rgVika.setChecked(isVikaProxyEnabled());
|
||||
|
||||
new VkAlertDialog.Builder(ctx)
|
||||
@@ -153,9 +153,9 @@ public class ProxyHook {
|
||||
if (rgZaborona.isChecked()) {
|
||||
Preferences.getPreferences().edit().putString("proxy", "zaborona").commit();
|
||||
restartApplication();
|
||||
} else if (rgRandomProxy.isChecked()) {
|
||||
Preferences.getPreferences().edit().putString("proxy", "randomproxy").commit();
|
||||
restartApplication();
|
||||
// } else if (rgRandomProxy.isChecked()) {
|
||||
// Preferences.getPreferences().edit().putString("proxy", "randomproxy").commit();
|
||||
// restartApplication();
|
||||
} else if (rgVika.isChecked()) {
|
||||
Preferences.getPreferences().edit().putString("proxy", "vika").commit();
|
||||
restartApplication();
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class TabletHook {
|
||||
public static boolean hook() {
|
||||
return AndroidUtils.isTablet() && !Preferences.getBoolValue("disableForceTabletMode", false);
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ public class TogglesHook {
|
||||
postsredesign();
|
||||
case FEATURE_IMAGE_QUALITY_UPGRADE -> MediaImageEncoder.needToSkipCompression();
|
||||
case FEATURE_MENU_GAMES_CAROUSEL -> miniapps();
|
||||
case FEATURE_TRAFFIC_SAVER -> !disableForceTrafficSaver();
|
||||
default -> true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package ru.vtosters.hooks;
|
||||
|
||||
import com.vk.dto.common.VerifyInfo;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.utils.VTVerifications;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
@@ -20,7 +21,7 @@ public class VerificationsHook {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!getBoolValue("VT_Verification", true)) {
|
||||
if (!getBoolValue("VT_Verification", true) || Preferences.serverFeaturesDisable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -32,7 +33,7 @@ public class VerificationsHook {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!getBoolValue("VT_Fire", true)) {
|
||||
if (!getBoolValue("VT_Fire", true) || Preferences.serverFeaturesDisable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -40,10 +41,6 @@ public class VerificationsHook {
|
||||
}
|
||||
|
||||
public static boolean hasDeveloper(JSONObject jSONObject) {
|
||||
if (!getBoolValue("VT_Dev", true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return VTVerifications.isDeveloper(VTVerifications.getId(jSONObject));
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.music.hook;
|
||||
package ru.vtosters.hooks.music;
|
||||
|
||||
import android.content.Context;
|
||||
import com.vk.music.fragment.MusicFragment;
|
||||
+14
-32
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.music.hook;
|
||||
package ru.vtosters.hooks.music;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClientImpl;
|
||||
@@ -8,45 +8,29 @@ import com.vk.music.bottomsheets.a.MusicAction;
|
||||
import com.vk.music.common.MusicPlaybackLaunchContext;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.lite.downloaders.AudioDownloader;
|
||||
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
|
||||
import ru.vtosters.lite.music.cache.MusicCacheImpl;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.music.VKXUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static bruhcollective.itaysonlab.libvkx.client.LibVKXClient.*;
|
||||
import static ru.vtosters.hooks.other.Preferences.milkshake;
|
||||
import static ru.vtosters.lite.music.cache.CacheDatabaseDelegate.isCached;
|
||||
import static ru.vtosters.lite.music.cache.CacheDatabaseDelegate.isVkxCached;
|
||||
import static ru.vtosters.lite.utils.NetworkUtils.isNetworkConnected;
|
||||
|
||||
public class MusicBottomSheetHook {
|
||||
public static ArrayList<MusicAction> hook(ArrayList<MusicAction> actions, MusicTrack musicTrack) {
|
||||
public static ArrayList<MusicAction> hook(final ArrayList<MusicAction> actions, final MusicTrack musicTrack) {
|
||||
if (musicTrack.F1()) return actions;
|
||||
|
||||
var trackid = asId(musicTrack);
|
||||
|
||||
if (isVkxInstalled()) {
|
||||
actions.add(getPlayInVKXAction());
|
||||
}
|
||||
|
||||
final var trackId = asId(musicTrack);
|
||||
if (isVkxInstalled()) actions.add(getPlayInVKXAction());
|
||||
if (isIntegrationEnabled()) {
|
||||
if (isVkxCached(trackid)) {
|
||||
actions.add(getRemoveCacheTrackVkxAction());
|
||||
} else if (isNetworkConnected()) {
|
||||
actions.add(addToCacheTrackVkxAction());
|
||||
}
|
||||
if (VKXUtils.isVkxCached(trackId)) actions.add(getRemoveCacheTrackVkxAction());
|
||||
else if (isNetworkConnected()) actions.add(addToCacheTrackVkxAction());
|
||||
} else {
|
||||
if (isCached(trackid)) {
|
||||
actions.add(getRemoveCacheTrackAction());
|
||||
} else if (isNetworkConnected()) {
|
||||
actions.add(addToCacheTrackAction());
|
||||
}
|
||||
if (MusicCacheImpl.isCachedTrack(trackId)) actions.add(getRemoveCacheTrackAction());
|
||||
else if (isNetworkConnected()) actions.add(addToCacheTrackAction());
|
||||
}
|
||||
|
||||
if (isNetworkConnected()) {
|
||||
actions.add(downloadAsMp3Action());
|
||||
}
|
||||
|
||||
if (isNetworkConnected()) actions.add(downloadAsMp3Action());
|
||||
return actions;
|
||||
}
|
||||
|
||||
@@ -54,9 +38,7 @@ public class MusicBottomSheetHook {
|
||||
public static ArrayList<MusicAction> hookDownloadBTN(ArrayList<MusicAction> actions, MusicTrack musicTrack) {
|
||||
if (musicTrack.F1()) return actions;
|
||||
|
||||
var trackid = asId(musicTrack);
|
||||
|
||||
if (isCached(trackid)) {
|
||||
if (MusicCacheImpl.isCachedTrack(musicTrack.y1())) {
|
||||
actions.add(new MusicAction(
|
||||
R.id.music_action_toggle_download,
|
||||
milkshake() ? R.drawable.ic_delete_outline_28 : R.drawable.ic_delete_24,
|
||||
@@ -85,7 +67,7 @@ public class MusicBottomSheetHook {
|
||||
if (isVkxInstalled()) actions.add(getPlayInVKXAction());
|
||||
|
||||
if (isIntegrationEnabled()) {
|
||||
if (isVkxCached(playlist.a, playlist.b)) {
|
||||
if (VKXUtils.isVkxCached(playlist.a, playlist.b)) {
|
||||
actions.add(getRemoveCacheTrackVkxAction());
|
||||
} else if (isNetworkConnected()) {
|
||||
actions.add(addToCacheTrackVkxAction());
|
||||
@@ -124,7 +106,7 @@ public class MusicBottomSheetHook {
|
||||
}
|
||||
|
||||
if (actionId == R.id.remove_from_cache) {
|
||||
CacheDatabaseDelegate.removeTrackFromCache(asId(track));
|
||||
MusicCacheImpl.removeTrack(asId(track));
|
||||
AndroidUtils.sendToast(AndroidUtils.getString("audio_deleted_from_cache"));
|
||||
return true;
|
||||
} else if (actionId == R.id.add_to_cache) {
|
||||
@@ -0,0 +1,16 @@
|
||||
package ru.vtosters.hooks.music;
|
||||
|
||||
import ru.vtosters.lite.music.cache.MusicCacheImpl;
|
||||
import ru.vtosters.lite.utils.music.MusicCacheStorageUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class MusicCacheFilesHook {
|
||||
public static File getTrackFile(String trackId) {
|
||||
return MusicCacheStorageUtils.getTrackFile(trackId);
|
||||
}
|
||||
|
||||
public static boolean isTrackExist(String trackId) {
|
||||
return MusicCacheImpl.isCachedTrack(trackId);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.music.hook;
|
||||
package ru.vtosters.hooks.music;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.AttrRes;
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.music.catalog.inject;
|
||||
package ru.vtosters.hooks.music.injectors;
|
||||
|
||||
import android.util.Log;
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
|
||||
@@ -12,7 +12,7 @@ import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
|
||||
import ru.vtosters.lite.music.cache.MusicCacheImpl;
|
||||
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
@@ -48,7 +48,7 @@ public class CatalogJsonInjector {
|
||||
setDefaultAudioPage(oldItems, catalog);
|
||||
}
|
||||
|
||||
if (CacheDatabaseDelegate.hasTracks() && !LibVKXClient.isIntegrationEnabled()) { // inj in playlist list
|
||||
if (!MusicCacheImpl.isEmpty() && !LibVKXClient.isIntegrationEnabled()) { // inj in playlist list
|
||||
var noPlaylists = !json.has("playlists");
|
||||
|
||||
if (noPlaylists) {
|
||||
@@ -91,7 +91,7 @@ public class CatalogJsonInjector {
|
||||
|
||||
fixDailyMix(blocks);
|
||||
|
||||
if (!isUsersCatalog || !CacheDatabaseDelegate.hasTracks() || LibVKXClient.isIntegrationEnabled()) {
|
||||
if (!isUsersCatalog || MusicCacheImpl.isEmpty() || LibVKXClient.isIntegrationEnabled()) {
|
||||
return; // early return if not users catalog or no tracks or integration enabled
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.music.cache.injectors;
|
||||
package ru.vtosters.hooks.music.injectors;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.text.TextUtils;
|
||||
@@ -12,7 +12,7 @@ import io.reactivex.ObservableOnSubscribe;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.downloaders.AudioDownloader;
|
||||
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
|
||||
import ru.vtosters.lite.music.cache.MusicCacheImpl;
|
||||
import ru.vtosters.lite.music.cache.helpers.PlaylistHelper;
|
||||
import ru.vtosters.lite.music.cache.helpers.TracklistHelper;
|
||||
|
||||
@@ -30,7 +30,7 @@ public class PlaylistInjector {
|
||||
}
|
||||
|
||||
public static boolean eligibleForOfflineCaching() {
|
||||
return CacheDatabaseDelegate.hasTracks();
|
||||
return !MusicCacheImpl.isEmpty();
|
||||
}
|
||||
|
||||
public static Observable<AudioGetPlaylist.c> injectGetPlaylist(AudioGetPlaylist audioGetPlaylist) {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.music.cache.injectors;
|
||||
package ru.vtosters.hooks.music.injectors;
|
||||
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import com.vk.music.model.IpcPlayerModelImpl;
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.music.cache.injectors;
|
||||
package ru.vtosters.hooks.music.injectors;
|
||||
|
||||
import android.util.Log;
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
|
||||
@@ -11,7 +11,7 @@ import io.reactivex.ObservableOnSubscribe;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
|
||||
import ru.vtosters.lite.music.cache.MusicCacheImpl;
|
||||
import ru.vtosters.lite.music.cache.helpers.PlaylistHelper;
|
||||
import ru.vtosters.lite.music.cache.helpers.TracklistHelper;
|
||||
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||
@@ -56,7 +56,7 @@ public class TracklistInjector {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (!CacheDatabaseDelegate.hasTracks()) {
|
||||
if (MusicCacheImpl.isEmpty()) {
|
||||
observableEmitter.b(parser.c(getEmptyCatalog()));
|
||||
} else {
|
||||
observableEmitter.b(parser.c(createVirtualCatalog(TracklistHelper.getTracks())));
|
||||
@@ -135,7 +135,7 @@ public class TracklistInjector {
|
||||
|
||||
button.put("action", action);
|
||||
button.put("block_id", "shuffle");
|
||||
button.put("ref_items_count", CacheDatabaseDelegate.getTrackCount());
|
||||
button.put("ref_items_count", MusicCacheImpl.getTracksCount());
|
||||
button.put("ref_layout_name", "list");
|
||||
button.put("ref_data_type", "music_audios");
|
||||
|
||||
@@ -158,7 +158,7 @@ public class TracklistInjector {
|
||||
|
||||
JSONArray blocks = firstSection.getJSONArray("blocks");
|
||||
|
||||
if (CacheDatabaseDelegate.hasTracks() && !LibVKXClient.isIntegrationEnabled()) { // inj in playlist list
|
||||
if (!MusicCacheImpl.isEmpty() && !LibVKXClient.isIntegrationEnabled()) { // inj in playlist list
|
||||
boolean noPlaylists = hasNoPlaylists(blocks);
|
||||
|
||||
if (noPlaylists) {
|
||||
@@ -29,7 +29,6 @@ public class Preferences {
|
||||
|
||||
GmsHook.fixGapps();
|
||||
ProxyUtils.setProxy();
|
||||
NewsFeedFiltersUtils.setupFilters();
|
||||
VTVerifications.load(application);
|
||||
LifecycleUtils.registerActivities(application);
|
||||
|
||||
@@ -177,6 +176,10 @@ public class Preferences {
|
||||
return getBoolValue("miniapps", true);
|
||||
}
|
||||
|
||||
public static boolean disableForceTrafficSaver() {
|
||||
return getBoolValue("disableForceTrafficSaver", false);
|
||||
}
|
||||
|
||||
public static boolean savemsgsett() {
|
||||
return getBoolValue("savemsgsett", false);
|
||||
}
|
||||
@@ -242,6 +245,10 @@ public class Preferences {
|
||||
return getBoolValue("autoalltranslate", false);
|
||||
}
|
||||
|
||||
public static boolean serverFeaturesDisable() {
|
||||
return getBoolValue("serverFeaturesDisable", false);
|
||||
}
|
||||
|
||||
public static boolean shortinfo() {
|
||||
return getBoolValue("shortinfo", true);
|
||||
}
|
||||
@@ -288,16 +295,16 @@ public class Preferences {
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public static boolean checkupdates() {
|
||||
return !getBoolValue("isRoamingState", false) && isValidSignature() && BuildConfig.BUILD_TYPE.equals("release");
|
||||
return !getBoolValue("isRoamingState", false) && isValidSignature() && BuildConfig.BUILD_TYPE.equals("release") && getBoolValue("autoupdates", true) && !serverFeaturesDisable();
|
||||
}
|
||||
|
||||
public static boolean isNewBuild() {
|
||||
if(Preferences.getBoolValue("invalidate_theme_cache_each_update",true))
|
||||
if (Preferences.getBoolValue("invalidate_theme_cache_each_update", true))
|
||||
try {
|
||||
return AndroidUtils.getGlobalContext()
|
||||
.getPackageManager()
|
||||
.getPackageInfo(AndroidUtils.getPackageName(), 0)
|
||||
.lastUpdateTime != getPreferences().getLong("setupTime", 0L);
|
||||
.getPackageManager()
|
||||
.getPackageInfo(AndroidUtils.getPackageName(), 0)
|
||||
.lastUpdateTime != getPreferences().getLong("setupTime", 0L);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -24,7 +24,10 @@ public class ProfileHook {
|
||||
|
||||
if (UsersList.hasDescription(userID)) {
|
||||
try {
|
||||
extendedUserProfile.z2 = Handler.getDescription(userID);
|
||||
String description = Handler.getDescription(userID);
|
||||
if (!TextUtils.isEmpty(description)) {
|
||||
extendedUserProfile.z2 = description;
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
Log.e(TAG, "null \"profiles\" node\n" + e);
|
||||
}
|
||||
|
||||
@@ -6,8 +6,9 @@ import com.vk.core.util.ToastUtils;
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import com.vk.dto.music.Playlist;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.MusicCacheFilesHook;
|
||||
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
|
||||
import ru.vtosters.hooks.music.MusicCacheFilesHook;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.music.cache.MusicCacheImpl;
|
||||
import ru.vtosters.lite.music.callback.MusicCallbackBuilder;
|
||||
import ru.vtosters.lite.music.converter.playlist.PlaylistConverter;
|
||||
import ru.vtosters.lite.music.downloader.AudioGet;
|
||||
@@ -32,13 +33,14 @@ import static ru.vtosters.lite.utils.AndroidUtils.getString;
|
||||
|
||||
public class AudioDownloader {
|
||||
public static final ExecutorService executor = Executors.newCachedThreadPool();
|
||||
public static final String dlpath = Preferences.getBoolValue("dldir", false) ? Environment.DIRECTORY_DOWNLOADS : Environment.DIRECTORY_MUSIC;
|
||||
|
||||
public static void downloadPlaylist(Playlist playlist) {
|
||||
var tracks = PlaylistConverter.getPlaylist(playlist);
|
||||
|
||||
var playlistName = IOUtils.getValidFileName(playlist.g);
|
||||
|
||||
var musicPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getAbsolutePath();
|
||||
var musicPath = Environment.getExternalStoragePublicDirectory(dlpath).getAbsolutePath();
|
||||
var downloadPath = musicPath + File.separator + playlistName;
|
||||
|
||||
var notificationId = playlistName.hashCode();
|
||||
@@ -58,10 +60,10 @@ public class AudioDownloader {
|
||||
}
|
||||
|
||||
public static void cacheTrack(MusicTrack track) {
|
||||
var trackId = track.y1();
|
||||
var trackId = LibVKXClient.asId(track);
|
||||
|
||||
if (CacheDatabaseDelegate.isCached(trackId)) {
|
||||
CacheDatabaseDelegate.removeTrackFromCache(LibVKXClient.asId(track));
|
||||
if (MusicCacheImpl.isCachedTrack(trackId)) {
|
||||
MusicCacheImpl.removeTrack(trackId);
|
||||
AndroidUtils.sendToast(AndroidUtils.getString("audio_deleted_from_cache"));
|
||||
return;
|
||||
}
|
||||
@@ -104,7 +106,7 @@ public class AudioDownloader {
|
||||
|
||||
var playlistName = "Audios of " + AccountManagerUtils.getUserId();
|
||||
|
||||
var musicPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getAbsolutePath();
|
||||
var musicPath = Environment.getExternalStoragePublicDirectory(dlpath).getAbsolutePath();
|
||||
var downloadPath = musicPath + File.separator + playlistName;
|
||||
|
||||
PlaylistDownloader.downloadPlaylist(
|
||||
@@ -121,7 +123,7 @@ public class AudioDownloader {
|
||||
return;
|
||||
}
|
||||
|
||||
var musicPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getAbsolutePath();
|
||||
var musicPath = Environment.getExternalStoragePublicDirectory(dlpath).getAbsolutePath();
|
||||
var tempId = track.d;
|
||||
var downloadPath = musicPath + File.separator;
|
||||
var notification = MusicNotificationBuilder.buildDownloadNotification(track, tempId);
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package ru.vtosters.lite.foaf;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vk.core.network.Network;
|
||||
import com.vtosters.lite.R;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@@ -15,13 +12,9 @@ import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.lite.net.Request;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -34,43 +27,15 @@ import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
|
||||
public class FoafBase {
|
||||
private static final Pattern FOAF_REGEX = Pattern.compile("<ya:created dc:date=\"(.+?)\"");
|
||||
private static final Pattern FOAF_REGEX_LAST_SEEN = Pattern.compile("<ya:lastLoggedIn dc:date=\"(.*)(((\\+|-)\\d\\d):(\\d\\d))\"");
|
||||
private static final String API_VKNEXT = "https://api.vtosters.app/v1/getBypassedOnlineInfo?json=1&ids=";
|
||||
private static final OkHttpClient client = VtOkHttpClient.getInstance();
|
||||
|
||||
public static long getLastSeen(long origtime, int id) throws ParseException {
|
||||
var request = new okhttp3.Request.a()
|
||||
.b(getLink(id))
|
||||
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8")).a();
|
||||
|
||||
String response = null;
|
||||
|
||||
try {
|
||||
response = client.a(request).execute().a().g();
|
||||
} catch (IOException e) {
|
||||
Log.e("FoafBase", e.getMessage());
|
||||
}
|
||||
|
||||
Matcher matcher = FOAF_REGEX_LAST_SEEN.matcher(response);
|
||||
|
||||
if (!matcher.find()) {
|
||||
return origtime;
|
||||
}
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
|
||||
sdf.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));
|
||||
Date date = sdf.parse(Objects.requireNonNull(matcher.group(1)));
|
||||
sdf.setTimeZone(TimeZone.getDefault());
|
||||
return sdf.parse(sdf.format(date)).getTime() / 1000;
|
||||
}
|
||||
|
||||
|
||||
public static JSONObject getBypassedOnlineInfo(int id) throws JSONException {
|
||||
var request = new okhttp3.Request.a()
|
||||
.b(API_VKNEXT + id)
|
||||
.a();
|
||||
|
||||
String response = null;
|
||||
String response;
|
||||
|
||||
var dummy = new JSONObject();
|
||||
dummy.put("last_seen", 0);
|
||||
@@ -86,7 +51,6 @@ public class FoafBase {
|
||||
}
|
||||
|
||||
public static JSONObject getBypassedOnlineInfo(String ids) {
|
||||
|
||||
var request = new okhttp3.Request.a()
|
||||
.b(API_VKNEXT + ids)
|
||||
.a();
|
||||
@@ -135,7 +99,15 @@ public class FoafBase {
|
||||
progressDialog.cancel();
|
||||
Matcher matcher = FOAF_REGEX.matcher(str);
|
||||
matcher.find();
|
||||
String normalHumanDate = getNormalHumanDate(Objects.requireNonNull(matcher.group(1)));
|
||||
|
||||
String m = matcher.group(1);
|
||||
|
||||
if (m == null) {
|
||||
LifecycleUtils.getCurrentActivity().runOnUiThread(() -> makeText(getGlobalContext(), context.getString(R.string.foaferr), LENGTH_SHORT).show());
|
||||
return;
|
||||
}
|
||||
|
||||
String normalHumanDate = getNormalHumanDate(m);
|
||||
|
||||
LifecycleUtils.getCurrentActivity().runOnUiThread(() -> new VkAlertDialog.Builder(context)
|
||||
.setTitle(R.string.addinf)
|
||||
@@ -147,17 +119,14 @@ public class FoafBase {
|
||||
.show());
|
||||
} catch (Exception e) {
|
||||
LifecycleUtils.getCurrentActivity().runOnUiThread(() -> makeText(getGlobalContext(), context.getString(R.string.foaferr), LENGTH_SHORT).show());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static long daysPassedFromFoafDate(String str) {
|
||||
try {
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
Date parse = new SimpleDateFormat("yyyy-MM-dd").parse(str.split(" ")[1]);
|
||||
return TimeUnit.DAYS.convert(new Date().getTime() - parse.getTime(), TimeUnit.MILLISECONDS);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.vk.dto.music.MusicTrack;
|
||||
import com.vtosters.lite.R;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@@ -22,8 +23,8 @@ public class Genius {
|
||||
|
||||
public static String getTextMusic(MusicTrack musictrack) {
|
||||
var uid = musictrack.y1();
|
||||
var artist = musictrack.C;
|
||||
var title = musictrack.f;
|
||||
var artist = removeExtras(musictrack.C);
|
||||
var title = removeExtras(musictrack.f);
|
||||
var duration = musictrack.h;
|
||||
|
||||
if (TextUtils.isEmpty(uid) || TextUtils.isEmpty(artist) || TextUtils.isEmpty(title) || duration == 0) {
|
||||
@@ -41,7 +42,7 @@ public class Genius {
|
||||
}
|
||||
|
||||
Request request = new Request.a()
|
||||
.b(URL + "/search/multi?q=" + URLEncoder.encode(artist + " " + track) + "&from_background=0")
|
||||
.b(URL + "/search/songs?q=" + URLEncoder.encode(artist + " " + track) + "&from_background=0" + "&page=1")
|
||||
.a("User-Agent", "Genius/5.14.0 (Android; Android 13; Google Pixel 4 XL)")
|
||||
.a("Authorization", KEY)
|
||||
.a("x-genius-app-background-request", "0")
|
||||
@@ -50,8 +51,8 @@ public class Genius {
|
||||
.a("Content-Type", "application/x-www-form-urlencoded")
|
||||
.b()
|
||||
.a();
|
||||
try {
|
||||
String payload = client.a(request).execute().a().g();
|
||||
try (Response resp = client.a(request).execute()) {
|
||||
String payload = resp.a().g();
|
||||
JSONArray sections = new JSONObject(payload).getJSONObject("response").getJSONArray("sections");
|
||||
|
||||
for (int i = 0; i < sections.length(); i++) {
|
||||
@@ -70,13 +71,19 @@ public class Genius {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AndroidUtils.getString("error_no_text");
|
||||
} catch (JSONException | IOException e) {
|
||||
return AndroidUtils.getString("error_no_text") + "\n\n" + AndroidUtils.getString(R.string.error) + ": \n" + e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public static String removeExtras(String title) {
|
||||
return title
|
||||
.replaceAll("[\\[\\]]", "(")
|
||||
.replaceAll("[()]", "")
|
||||
.trim();
|
||||
}
|
||||
|
||||
private static String getText(String track) {
|
||||
Request request = new Request.a()
|
||||
.b(URL + track + "?text_format=plain")
|
||||
|
||||
@@ -7,14 +7,13 @@ import androidx.annotation.Nullable;
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import com.vtosters.lite.R;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.*;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.lite.downloaders.AudioDownloader;
|
||||
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
|
||||
import ru.vtosters.lite.music.cache.MusicCacheImpl;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -47,7 +46,7 @@ public class LastFMScrobbler {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Preferences.autocache() && !CacheDatabaseDelegate.isCached(uid)) {
|
||||
if (Preferences.autocache() && !MusicCacheImpl.isCachedTrack(uid)) {
|
||||
if (LibVKXClient.isIntegrationEnabled()) {
|
||||
LibVKXClient.getInstance().runOnService(service -> {
|
||||
try {
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
package ru.vtosters.lite.music;
|
||||
|
||||
import android.util.Log;
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import java8.util.concurrent.CompletableFuture;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
|
||||
import ru.vtosters.lite.music.converter.ts.FFMpeg;
|
||||
import ru.vtosters.lite.music.converter.ts.TSMerger;
|
||||
import ru.vtosters.lite.music.downloader.ThumbnailDownloader;
|
||||
import ru.vtosters.lite.music.interfaces.ITrackDownloader;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.IOUtils;
|
||||
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class M3UDownloader implements ITrackDownloader {
|
||||
private static final OkHttpClient client = VtOkHttpClient.getInstance();
|
||||
|
||||
public static M3UDownloader getInstance() {
|
||||
return Holder.INSTANCE;
|
||||
}
|
||||
|
||||
public static String getTitle(MusicTrack track) {
|
||||
String title = null;
|
||||
|
||||
if (track.f != null) {
|
||||
title = track.f;
|
||||
if (!track.g.isEmpty()) {
|
||||
title += " (" + track.g + ")";
|
||||
}
|
||||
}
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
public void downloadTrack(MusicTrack track, File outDir, Callback callback, boolean cache) {
|
||||
if (track.D.isEmpty()) {
|
||||
Log.d("TrackDownloader", "link error: " + track.y1() + ", title: " + M3UDownloader.getTitle(track));
|
||||
callback.onFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Request request = new Request.a().b(track.D).a();
|
||||
String response = client.a(request).execute().a().g();
|
||||
parse(response, outDir, callback, track, cache);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
callback.onFailure();
|
||||
}
|
||||
}
|
||||
|
||||
private void parse(String payload, File outDir, Callback callback, MusicTrack track, boolean cache) throws UnsupportedEncodingException {
|
||||
if (cache) downloadThumbnails(track);
|
||||
|
||||
VKM3UParser parser = new VKM3UParser(track.D.substring(0, track.D.lastIndexOf("/") + 1), payload);
|
||||
AtomicInteger progress = new AtomicInteger(0);
|
||||
List<CompletableFuture<Void>> futures = createFutures(parser, progress, callback, track);
|
||||
|
||||
var resultTs = getResultTsFile(track);
|
||||
var resultMp3 = getResultMp3File(outDir, cache, track);
|
||||
|
||||
callback.onProgress(5);
|
||||
var future = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
||||
future.join();
|
||||
future.exceptionally(throwable -> {
|
||||
callback.onFailure();
|
||||
return null;
|
||||
}).thenApply(v -> TSMerger.merge(getTsesDir(track), resultTs))
|
||||
.thenApply(mergeResult -> mergeResult && FFMpeg.convert(resultTs, resultMp3.getAbsolutePath(), track))
|
||||
.thenApply(convertResult -> {
|
||||
if (convertResult)
|
||||
callback.onProgress(10 + Math.round(80.0f * progress.addAndGet(1) / parser.mTransportStreams.size()));
|
||||
else callback.onFailure();
|
||||
return convertResult;
|
||||
}).thenRun(() -> IOUtils.deleteRecursive(getTsesDir(track))).thenRun(() -> {
|
||||
callback.onSuccess();
|
||||
if (cache) CacheDatabaseDelegate.insertTrack(track);
|
||||
});
|
||||
}
|
||||
|
||||
private void downloadThumbnails(MusicTrack track) {
|
||||
try {
|
||||
ThumbnailDownloader.downloadThumbnails(track);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private List<CompletableFuture<Void>> createFutures(VKM3UParser parser, AtomicInteger progress, Callback callback, MusicTrack track) {
|
||||
List<CompletableFuture<Void>> futures = new ArrayList<>(parser.mTransportStreams.size());
|
||||
|
||||
var tses = parser.mTransportStreams;
|
||||
for (var i = 0; i < tses.size(); ++i) {
|
||||
final var ts = tses.get(i);
|
||||
final var filename = i + ".ts";
|
||||
futures.add(CompletableFuture.runAsync(() -> processTransportStream(parser, ts, filename, progress, tses.size(), callback, track)));
|
||||
}
|
||||
return futures;
|
||||
}
|
||||
|
||||
private void processTransportStream(VKM3UParser parser, TransportStream ts, String filename, AtomicInteger progress, int size, Callback callback, MusicTrack track) {
|
||||
try {
|
||||
InputStream mediaIs = IOUtils.openStream(ts.getMediaSegmentUri());
|
||||
byte[] content;
|
||||
if (ts.needDecoding()) {
|
||||
InputStream keyPubIs = IOUtils.openStream(ts.getKeyURL());
|
||||
content = IOUtils.decodeStream(mediaIs, IOUtils.readFully(keyPubIs));
|
||||
keyPubIs.close();
|
||||
} else {
|
||||
content = IOUtils.readFully(mediaIs);
|
||||
}
|
||||
File tsDump = new File(getTsesDir(track), filename);
|
||||
IOUtils.writeToFile(tsDump, content);
|
||||
callback.onProgress(10 + Math.round(80.0f * progress.addAndGet(1) / size));
|
||||
callback.onSizeReceived((long) content.length * size, parser.mHeapSize);
|
||||
mediaIs.close();
|
||||
} catch (IOException | NoSuchPaddingException | NoSuchAlgorithmException |
|
||||
InvalidAlgorithmParameterException | InvalidKeyException e) {
|
||||
callback.onFailure();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private File getTsesDir(MusicTrack track) {
|
||||
var filesDir = AndroidUtils.getGlobalContext().getFilesDir();
|
||||
var tsesDir = new File(filesDir, String.valueOf(track.d));
|
||||
tsesDir.mkdirs();
|
||||
return tsesDir;
|
||||
}
|
||||
|
||||
private File getResultTsFile(MusicTrack track) {
|
||||
return new File(getTsesDir(track), "result.ts");
|
||||
}
|
||||
|
||||
private File getResultMp3File(File outDir, boolean cache, MusicTrack track) {
|
||||
var fileName = IOUtils.getValidFileName((cache ? "track" : track.C + " - " + getTitle(track)) + ".mp3");
|
||||
return new File(outDir, fileName);
|
||||
}
|
||||
|
||||
// Initialization-on-demand
|
||||
private static class Holder {
|
||||
private static final M3UDownloader INSTANCE = new M3UDownloader();
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package ru.vtosters.lite.music;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
public class TransportStream {
|
||||
|
||||
private final String mMediaSegmentUri;
|
||||
private String mKeyUri;
|
||||
private String mMediaSegmentName;
|
||||
|
||||
public TransportStream(String baseURI, String mediaSegmentName) {
|
||||
this.mMediaSegmentUri = baseURI + mediaSegmentName;
|
||||
}
|
||||
|
||||
public TransportStream(String keyURI, String baseURI, String mediaSegmentName) {
|
||||
this.mKeyUri = keyURI;
|
||||
this.mMediaSegmentUri = baseURI + mediaSegmentName;
|
||||
this.mMediaSegmentName = mediaSegmentName;
|
||||
}
|
||||
|
||||
public boolean needDecoding() {
|
||||
return !TextUtils.isEmpty(mKeyUri);
|
||||
}
|
||||
|
||||
public String getKeyURL() {
|
||||
return mKeyUri;
|
||||
}
|
||||
|
||||
public String getMediaSegmentUri() {
|
||||
return this.mMediaSegmentUri;
|
||||
}
|
||||
|
||||
public String getMediaSegmentName() {
|
||||
return this.mMediaSegmentName;
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
package ru.vtosters.lite.music;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* The parser for extended M3U playlist format used by VK.
|
||||
*
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8216#ref-M3U">M3U</a>
|
||||
**/
|
||||
public class VKM3UParser {
|
||||
//Playlist types
|
||||
static public int PLAYLIST_TYPE_VOD = 0;
|
||||
static public int PLAYLIST_TYPE_EVENT = 1;
|
||||
private final String mData;
|
||||
//region Extended M3U global extensions
|
||||
public List<TransportStream> mTransportStreams = new ArrayList<>();
|
||||
/**
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.1.2">EXT-X-VERSION</a>
|
||||
**/
|
||||
public int mVersion = -1;
|
||||
/**
|
||||
* The EXT-X-ALLOW-CACHE tag is used in protocol version 6 or lower.
|
||||
* If the protocol version is upgraded by VK, we will not support that.
|
||||
**/
|
||||
public boolean mAllowCache = false;
|
||||
/**
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.3.1">EXT-X-TARGETDURATION</a>
|
||||
**/
|
||||
public int mTargetDuration = -1;
|
||||
/**
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.3.2">EXT-X-MEDIA-SEQUENCE</a>
|
||||
**/
|
||||
public int mMediaSequence = -1;
|
||||
/**
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.3.3">EXT-X-DISCONTINUITY-SEQUENCE</a>
|
||||
**/
|
||||
public int mDiscontinuitySequence = -1;
|
||||
//endregion
|
||||
/**
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.3.5">EXT-X-PLAYLIST-TYPE</a>
|
||||
**/
|
||||
public int mPlaylistType = -1;
|
||||
/**
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.3.6">EXT-X-I-FRAMES-ONLY</a>
|
||||
**/
|
||||
public boolean mIFramesOnly = false;
|
||||
public long mHeapSize = 0;
|
||||
|
||||
public VKM3UParser(String baseUri, String data) {
|
||||
mData = data;
|
||||
init(baseUri);
|
||||
}
|
||||
|
||||
public static boolean isTS(String str) {
|
||||
return str.matches(".+\\.ts.*");
|
||||
}
|
||||
|
||||
private void init(String baseUri) {
|
||||
if (TextUtils.isEmpty(mData)) throw new NullPointerException("mData==null");
|
||||
Scanner scanner = new Scanner(mData);
|
||||
String line = scanner.nextLine();
|
||||
if (!"#EXTM3U".equals(line))
|
||||
throw new IllegalStateException(String.format("Unknown initial M3U tag: %s", line));
|
||||
boolean aes128 = false;
|
||||
String keyUri = "";
|
||||
while (scanner.hasNextLine()) {
|
||||
line = scanner.nextLine();
|
||||
if ('#' == line.charAt(0)) {
|
||||
parseTag(line);
|
||||
if (line.startsWith("#EXT-X-KEY:") && line.contains("METHOD=AES-128")) {
|
||||
aes128 = true;
|
||||
keyUri = getKeyUri(line, baseUri);
|
||||
}
|
||||
} else if (isTS(line)) {
|
||||
addTransportStream(aes128, keyUri, baseUri, line);
|
||||
aes128 = false;
|
||||
} else {
|
||||
throw new RuntimeException(String.format("Failed to parse: %s", line));
|
||||
}
|
||||
mHeapSize += line.getBytes().length;
|
||||
}
|
||||
}
|
||||
|
||||
private void parseTag(String line) {
|
||||
if (line.startsWith("#EXT-X-VERSION:"))
|
||||
mVersion = Integer.parseInt(line.substring(15));
|
||||
else if (line.startsWith("#EXT-X-ALLOW-CACHE:"))
|
||||
mAllowCache = "YES".equalsIgnoreCase(line.substring(19));
|
||||
else if (line.startsWith("#EXT-X-TARGETDURATION:"))
|
||||
mTargetDuration = Integer.parseInt(line.substring(22));
|
||||
else if (line.startsWith("#EXT-X-MEDIA-SEQUENCE:"))
|
||||
mMediaSequence = Integer.parseInt(line.substring(22));
|
||||
else if (line.startsWith("#EXT-X-DISCONTINUITY-SEQUENCE:"))
|
||||
mDiscontinuitySequence = Integer.parseInt(line.substring(30));
|
||||
else if (line.startsWith("#EXT-X-PLAYLIST-TYPE:"))
|
||||
parsePlaylistType(line.substring(21));
|
||||
else if (line.startsWith("#EXT-X-I-FRAMES-ONLY"))
|
||||
mIFramesOnly = true;
|
||||
}
|
||||
|
||||
private void parsePlaylistType(String type) {
|
||||
switch (type) {
|
||||
case "VOD" -> mPlaylistType = PLAYLIST_TYPE_VOD;
|
||||
case "EVENT" -> mPlaylistType = PLAYLIST_TYPE_EVENT;
|
||||
default -> throw new IllegalStateException(String.format("Unknown playlist type: %s", type));
|
||||
}
|
||||
}
|
||||
|
||||
private String getKeyUri(String line, String baseUri) {
|
||||
String substr = line.substring(11);
|
||||
substr = substr.substring(substr.indexOf('"') + 1, substr.lastIndexOf('"'));
|
||||
//TODO: supposed endpoint
|
||||
return substr.startsWith("http") ? substr : baseUri + substr;
|
||||
}
|
||||
|
||||
private void addTransportStream(boolean aes128, String keyUri, String baseUri, String line) {
|
||||
TransportStream ts = aes128
|
||||
? new TransportStream(keyUri, baseUri, line)
|
||||
: new TransportStream(baseUri, line);
|
||||
mTransportStreams.add(ts);
|
||||
}
|
||||
}
|
||||
@@ -1,343 +0,0 @@
|
||||
package ru.vtosters.lite.music.cache;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
import android.database.SQLException;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.os.RemoteException;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import bruhcollective.itaysonlab.libvkx.ILibVkxService;
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClientImpl;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import com.vtosters.lite.R;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static ru.vtosters.lite.music.cache.FileCacheImplementation.getCacheDir;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
|
||||
import static ru.vtosters.lite.utils.IOUtils.deleteRecursive;
|
||||
|
||||
public class CacheDatabaseDelegate {
|
||||
private static final int DB_VERSION = 0x1;
|
||||
private static final String DB_NAME = "vt_lite_cache.db";
|
||||
private static final String TABLE_NAME = "tracks";
|
||||
private static final String COLUMN_ID = "id";
|
||||
private static final String COLUMN_TRACK_ID = "trackId";
|
||||
private static final String COLUMN_ALBUM_ID = "albumId";
|
||||
private static final String COLUMN_TITLE = "title";
|
||||
private static final String COLUMN_SUBTITLE = "subtitle";
|
||||
private static final String COLUMN_ARTIST = "artist";
|
||||
private static final String COLUMN_ALBUM_TITLE = "albumTitle";
|
||||
private static final String COLUMN_EXPLICIT = "explicit";
|
||||
private static final String COLUMN_HAS_ARTWORK = "hasArtwork";
|
||||
private static final String COLUMN_DURATION = "duration";
|
||||
private static DbHelper helperInstance;
|
||||
|
||||
protected static DbHelper getHelper() {
|
||||
if (helperInstance == null) helperInstance = new DbHelper(getGlobalContext());
|
||||
return helperInstance;
|
||||
}
|
||||
|
||||
// You MUST call this method ONLY AFTER TRACK IS DOWNLOADED!
|
||||
public static void insertTrack(MusicTrack track) {
|
||||
try {
|
||||
var json = track.J();
|
||||
var albumNode = json.optJSONObject("album");
|
||||
|
||||
var hasArtwork = false;
|
||||
var albumId = -1;
|
||||
var albumName = "";
|
||||
|
||||
if (albumNode != null) {
|
||||
hasArtwork = albumNode.has("thumb");
|
||||
albumId = albumNode.getInt("id");
|
||||
albumName = albumNode.getString("title");
|
||||
}
|
||||
|
||||
var formula = String.format(
|
||||
"INSERT INTO %s (%s, %s, %s, %s, %s, %s, %s, %s, %s) VALUES ('%s', %s, '%s', '%s', '%s', '%s', %s, %s, %s)",
|
||||
TABLE_NAME,
|
||||
COLUMN_TRACK_ID, COLUMN_ALBUM_ID, COLUMN_TITLE, COLUMN_SUBTITLE, COLUMN_ARTIST, COLUMN_ALBUM_TITLE, COLUMN_EXPLICIT, COLUMN_DURATION, COLUMN_HAS_ARTWORK,
|
||||
track.y1(),
|
||||
albumId,
|
||||
URLEncoder.encode(json.getString("title"), "UTF-8"),
|
||||
URLEncoder.encode(json.optString("subtitle"), "UTF-8"),
|
||||
URLEncoder.encode(json.getString("artist"), "UTF-8"),
|
||||
URLEncoder.encode(albumName, "UTF-8"),
|
||||
json.optInt("is_explicit"),
|
||||
json.getInt("duration"),
|
||||
hasArtwork ? 1 : 0
|
||||
);
|
||||
getHelper().getReadableDatabase().execSQL(formula);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
ToastUtils.a(AndroidUtils.getString(R.string.track_bd_insert_err) + " [" + e.getMessage() + "]", true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void insertTracks(List<MusicTrack> tracks) {
|
||||
for (var track : tracks) insertTrack(track);
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
getHelper().getReadableDatabase().execSQL(String.format("DELETE FROM %s", TABLE_NAME));
|
||||
deleteRecursive(getCacheDir());
|
||||
sendToast(AndroidUtils.getString(R.string.cached_tracks_deleted));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static JSONObject reconstructFromDb(Cursor cursor) {
|
||||
try {
|
||||
var trackId = cursor.getString(getColumnIndex(cursor, COLUMN_TRACK_ID));
|
||||
var splits = trackId.split("_");
|
||||
var id = Integer.parseInt(splits[1]);
|
||||
var ownerId = Integer.parseInt(splits[0]);
|
||||
|
||||
return new JSONObject()
|
||||
.put("url", FileCacheImplementation.getServerPath())
|
||||
.put("id", id)
|
||||
.put("owner_id", ownerId)
|
||||
.put("title", URLDecoder.decode(cursor.getString(getColumnIndex(cursor, COLUMN_TITLE)), "UTF-8"))
|
||||
.put("subtitle", URLDecoder.decode(cursor.getString(getColumnIndex(cursor, COLUMN_SUBTITLE)), "UTF-8"))
|
||||
.put("artist", URLDecoder.decode(cursor.getString(getColumnIndex(cursor, COLUMN_ARTIST)), "UTF-8"))
|
||||
.put("duration", cursor.getInt(getColumnIndex(cursor, COLUMN_DURATION)))
|
||||
.put("is_explicit", cursor.getInt(getColumnIndex(cursor, COLUMN_EXPLICIT)))
|
||||
.put("access_key", 2281488)
|
||||
.putOpt("album", reconstructAlbumFromDb(cursor, trackId));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return new JSONObject();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JSONObject reconstructAlbumFromDb(Cursor cursor, String trackId) {
|
||||
try {
|
||||
if (!FileCacheImplementation.getTrackThumbnail(trackId, 300).exists()
|
||||
&& !FileCacheImplementation.getTrackThumbnail(trackId, 600).exists()
|
||||
&& !FileCacheImplementation.getTrackThumbnail(trackId, 1200).exists()
|
||||
) {
|
||||
var ownerId = Integer.parseInt(trackId.split("_")[1]);
|
||||
return new JSONObject()
|
||||
.put("id", cursor.getInt(getColumnIndex(cursor, COLUMN_ALBUM_ID)))
|
||||
.put("owner_id", ownerId)
|
||||
.put("title", URLDecoder.decode(cursor.getString(getColumnIndex(cursor, COLUMN_ALBUM_TITLE)), "UTF-8"))
|
||||
.putOpt("thumb", reconstructAlbumThumbFromDb(cursor, trackId));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JSONObject reconstructAlbumThumbFromDb(Cursor cursor, String trackId) {
|
||||
try {
|
||||
if (cursor.getInt(getColumnIndex(cursor, COLUMN_HAS_ARTWORK)) != 0)
|
||||
new JSONObject()
|
||||
.put("height", 600)
|
||||
.put("width", 600)
|
||||
.putOpt("photo_300", FileCacheImplementation.getFileUri(FileCacheImplementation.getTrackThumbnail(trackId, 300)))
|
||||
.putOpt("photo_600", FileCacheImplementation.getFileUri(FileCacheImplementation.getTrackThumbnail(trackId, 600)))
|
||||
.putOpt("photo_1200", FileCacheImplementation.getFileUri(FileCacheImplementation.getTrackThumbnail(trackId, 1200)));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int getColumnIndex(Cursor cursor, String name) {
|
||||
return cursor.getColumnIndexOrThrow(name);
|
||||
}
|
||||
|
||||
public static boolean hasTracks() {
|
||||
if (LibVKXClient.isIntegrationEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var formula = String.format(
|
||||
"SELECT COUNT(%s) FROM %s",
|
||||
COLUMN_ID,
|
||||
TABLE_NAME
|
||||
);
|
||||
var cursor = getHelper().getReadableDatabase().rawQuery(formula, null);
|
||||
if (cursor != null) {
|
||||
cursor.moveToFirst();
|
||||
int count = cursor.getInt(0);
|
||||
cursor.close();
|
||||
return count > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static List<MusicTrack> getTracks() {
|
||||
return getTracks(String.format(
|
||||
"SELECT * FROM %s",
|
||||
TABLE_NAME
|
||||
));
|
||||
}
|
||||
|
||||
public static List<MusicTrack> getTracksAsPlaylist() {
|
||||
return getTracks(String.format(
|
||||
"SELECT * FROM %s WHERE %s > -1 GROUP BY %s HAVING COUNT(*) > 1 ORDER by id DESC",
|
||||
TABLE_NAME,
|
||||
COLUMN_ALBUM_ID,
|
||||
COLUMN_ALBUM_ID
|
||||
));
|
||||
}
|
||||
|
||||
public static List<MusicTrack> getTracksByAlbum(String id) {
|
||||
return getTracks(String.format(
|
||||
"SELECT COUNT(%s) FROM %s WHERE %s = %s",
|
||||
COLUMN_ID,
|
||||
TABLE_NAME,
|
||||
COLUMN_ALBUM_ID,
|
||||
id
|
||||
));
|
||||
}
|
||||
|
||||
public static List<MusicTrack> getTracksByAlbumOne(String id) {
|
||||
return getTracks(String.format(
|
||||
"SELECT * FROM %s WHERE %s = %s LIMIT 1",
|
||||
TABLE_NAME,
|
||||
COLUMN_ALBUM_ID,
|
||||
id
|
||||
));
|
||||
}
|
||||
|
||||
public static List<MusicTrack> getTracks(String query) {
|
||||
List<MusicTrack> list = new ArrayList<>();
|
||||
try (Cursor cursor = getHelper().getReadableDatabase().rawQuery(query, new String[0])) {
|
||||
while (cursor.moveToNext()) {
|
||||
list.add(new MusicTrack(reconstructFromDb(cursor)));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static boolean isCached(String trackId) {
|
||||
var formula = String.format(
|
||||
"SELECT COUNT(%s) FROM %s WHERE %s = '%s'",
|
||||
COLUMN_ID,
|
||||
TABLE_NAME,
|
||||
COLUMN_TRACK_ID,
|
||||
trackId
|
||||
);
|
||||
try {
|
||||
Cursor size = getHelper().getReadableDatabase().rawQuery(formula, null);
|
||||
if (size != null) {
|
||||
size.moveToFirst();
|
||||
int count = size.getInt(0);
|
||||
size.close();
|
||||
return count != 0;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isVkxCached(int playlist_id, int owner_id) {
|
||||
return LibVKXClient.getInstance().runOnServiceSync(new LibVKXClientImpl.LibVKXActionGeneric<>() {
|
||||
@Override
|
||||
public Boolean run(ILibVkxService service) {
|
||||
try {
|
||||
return service.isPlaylistCached(playlist_id, owner_id);
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean defaultValue() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean isVkxCached(String trackId) {
|
||||
return LibVKXClient.getInstance().runOnServiceSync(new LibVKXClientImpl.LibVKXActionGeneric<>() {
|
||||
@Override
|
||||
public Boolean run(ILibVkxService service) {
|
||||
try {
|
||||
var splits = trackId.split("_");
|
||||
var id = Integer.parseInt(splits[1]);
|
||||
var owner = Integer.parseInt(splits[0]);
|
||||
return service.isTrackCached(id, owner);
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean defaultValue() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void removeTrackFromCache(String trackId) {
|
||||
deleteRecursive(FileCacheImplementation.getTrackFolder(trackId));
|
||||
|
||||
var formula = String.format(
|
||||
"DELETE FROM %s WHERE %s = '%s'",
|
||||
TABLE_NAME,
|
||||
COLUMN_TRACK_ID,
|
||||
trackId
|
||||
);
|
||||
getHelper().getWritableDatabase().execSQL(formula);
|
||||
}
|
||||
|
||||
public static long getTrackCount() {
|
||||
if (!LibVKXClient.isIntegrationEnabled())
|
||||
return DatabaseUtils.queryNumEntries(getHelper().getReadableDatabase(), TABLE_NAME);
|
||||
return LibVKXClient.getInstance().runOnServiceSync(new LibVKXClientImpl.LibVKXActionGeneric<Long>() {
|
||||
@Override
|
||||
public Long run(ILibVkxService service) {
|
||||
try {
|
||||
return (long) service.getCache().size();
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
return defaultValue();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long defaultValue() {
|
||||
return 0L;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static class DbHelper extends SQLiteOpenHelper {
|
||||
public DbHelper(Context context) {
|
||||
super(context, DB_NAME, null, DB_VERSION);
|
||||
}
|
||||
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
var formula = String.format(
|
||||
"CREATE TABLE %s (%s INTEGER PRIMARY KEY AUTOINCREMENT, %s TEXT, %s INTEGER, %s TEXT, %s TEXT, %s TEXT, %s TEXT, %s INTEGER, %s INTEGER, %s INTEGER)",
|
||||
TABLE_NAME,
|
||||
COLUMN_ID, COLUMN_TRACK_ID, COLUMN_ALBUM_ID, COLUMN_TITLE, COLUMN_SUBTITLE, COLUMN_ARTIST, COLUMN_ALBUM_TITLE, COLUMN_EXPLICIT, COLUMN_DURATION, COLUMN_HAS_ARTWORK
|
||||
);
|
||||
db.execSQL(formula);
|
||||
}
|
||||
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package ru.vtosters.lite.music.cache;
|
||||
|
||||
import android.net.Uri;
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import ru.vtosters.hooks.MusicCacheFilesHook;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.IOUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class FileCacheImplementation {
|
||||
|
||||
public static void clear() {
|
||||
CacheDatabaseDelegate.clear();
|
||||
IOUtils.deleteRecursive(getCacheDir(), false);
|
||||
}
|
||||
|
||||
public static File getCacheDir() {
|
||||
return AndroidUtils.getGlobalContext().getExternalFilesDir("vt_tracks");
|
||||
}
|
||||
|
||||
public static File getTrackFolder(String trackId) {
|
||||
var dir = new File(getCacheDir(), trackId);
|
||||
dir.mkdirs();
|
||||
return dir;
|
||||
}
|
||||
|
||||
public static File getThumbnailsFolder(String trackId) {
|
||||
var dir = new File(getTrackFolder(trackId), "thumbs");
|
||||
dir.mkdirs();
|
||||
return dir;
|
||||
}
|
||||
|
||||
public static File getTrackFile(MusicTrack track) {
|
||||
return MusicCacheFilesHook.getTrackFile(track.y1());
|
||||
}
|
||||
|
||||
public static File getTrackThumbnail(String trackId, int factor) {
|
||||
return new File(getThumbnailsFolder(trackId), "thumb_" + factor + ".png");
|
||||
}
|
||||
|
||||
public static String getFileUri(File file) {
|
||||
if (!file.exists()) return null;
|
||||
return Uri.fromFile(file).toString();
|
||||
}
|
||||
|
||||
public static String getServerPath() {
|
||||
return "https://vtosters.app";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package ru.vtosters.lite.music.cache;
|
||||
|
||||
import android.content.Context;
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import ru.vtosters.lite.music.cache.db.MusicCacheDb;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MusicCacheDbDelegate {
|
||||
static synchronized private MusicCacheDb connectToDb(Context context) {
|
||||
synchronized (MusicCacheDb.class) {
|
||||
return new MusicCacheDb(context);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addTrack(Context context,
|
||||
String trackId,
|
||||
String albumId,
|
||||
String title,
|
||||
String subtitle,
|
||||
String artist,
|
||||
String albumTitle,
|
||||
boolean explicit,
|
||||
int duration,
|
||||
boolean hasArtwork) {
|
||||
try (var db = connectToDb(context)) {
|
||||
db.addTrack(
|
||||
trackId,
|
||||
albumId,
|
||||
title,
|
||||
subtitle,
|
||||
artist,
|
||||
albumTitle,
|
||||
explicit,
|
||||
duration,
|
||||
hasArtwork);
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeTrack(Context context, String trackId) {
|
||||
try (var db = connectToDb(context)) {
|
||||
db.deleteTrack(trackId);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<MusicTrack> getAllTracks(Context context) {
|
||||
try (var db = connectToDb(context)) {
|
||||
return db.getAllTracks();
|
||||
}
|
||||
}
|
||||
|
||||
public static List<MusicTrack> getAlbumById(Context context, String albumId) {
|
||||
try (var db = connectToDb(context)) {
|
||||
return db.getAlbum(albumId);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<MusicTrack> getFirstAlbumTrack(Context context, String albumId) {
|
||||
try (var db = connectToDb(context)) {
|
||||
return db.getFirstAlbumTrack(albumId);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<MusicTrack> getPlaylist(Context context) {
|
||||
try (var db = connectToDb(context)) {
|
||||
return db.getPlaylist();
|
||||
}
|
||||
}
|
||||
|
||||
public static long getTracksCount(Context context) {
|
||||
try (var db = connectToDb(context)) {
|
||||
return db.getTracksCount();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isCachedTrack(Context context, String trackId) {
|
||||
try (var db = connectToDb(context)) {
|
||||
return db.isCachedTrack(trackId);
|
||||
}
|
||||
}
|
||||
|
||||
public static void drop(Context context) {
|
||||
context.deleteDatabase(MusicCacheDb.Constants.DB_NAME);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package ru.vtosters.lite.music.cache;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.text.TextUtils;
|
||||
import bruhcollective.itaysonlab.libvkx.ILibVkxService;
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClientImpl;
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.music.MusicCacheStorageUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MusicCacheImpl {
|
||||
public static void addTrack(MusicTrack track) {
|
||||
MusicCacheDbDelegate.addTrack(
|
||||
AndroidUtils.getGlobalContext(),
|
||||
track.y1(),
|
||||
track.I != null ? track.I.getId() + "" : "-1",
|
||||
track.f,
|
||||
!TextUtils.isEmpty(track.g) ? track.g : "",
|
||||
track.C,
|
||||
track.I != null ? track.I.getTitle() : "",
|
||||
track.K,
|
||||
track.h,
|
||||
track.I != null && track.I.u1() != null);
|
||||
}
|
||||
|
||||
public static void removeTrack(String trackId) {
|
||||
MusicCacheDbDelegate.removeTrack(AndroidUtils.getGlobalContext(), trackId);
|
||||
MusicCacheStorageUtils.removeTrackDirById(trackId);
|
||||
}
|
||||
|
||||
public static List<MusicTrack> getAllTracks() {
|
||||
return MusicCacheDbDelegate.getAllTracks(AndroidUtils.getGlobalContext());
|
||||
}
|
||||
|
||||
public static List<MusicTrack> getAlbumById(String albumId) {
|
||||
return MusicCacheDbDelegate.getAlbumById(AndroidUtils.getGlobalContext(), albumId);
|
||||
}
|
||||
|
||||
public static List<MusicTrack> getFirstAlbumTrack(String albumId) {
|
||||
return MusicCacheDbDelegate.getFirstAlbumTrack(AndroidUtils.getGlobalContext(), albumId);
|
||||
}
|
||||
|
||||
public static List<MusicTrack> getPlaylist() {
|
||||
return MusicCacheDbDelegate.getPlaylist(AndroidUtils.getGlobalContext());
|
||||
}
|
||||
|
||||
public static long getTracksCount() {
|
||||
return !LibVKXClient.isIntegrationEnabled()
|
||||
? MusicCacheDbDelegate.getTracksCount(AndroidUtils.getGlobalContext())
|
||||
: LibVKXClient.getInstance().runOnServiceSync(
|
||||
new LibVKXClientImpl.LibVKXActionGeneric<Long>() {
|
||||
@Override
|
||||
public Long run(ILibVkxService service) {
|
||||
try {
|
||||
return (long) service.getCache().size();
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
return defaultValue();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long defaultValue() {
|
||||
return 0L;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean isCachedTrack(String trackId) {
|
||||
return MusicCacheDbDelegate.isCachedTrack(AndroidUtils.getGlobalContext(), trackId);
|
||||
}
|
||||
|
||||
public static boolean isEmpty() {
|
||||
return !LibVKXClient.isIntegrationEnabled() && getTracksCount() == 0L;
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
MusicCacheDbDelegate.drop(AndroidUtils.getGlobalContext());
|
||||
MusicCacheStorageUtils.clear();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user