Compare commits
125
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44fa23020e | ||
|
|
4cdcf9aee0 | ||
|
|
63c5262444 | ||
|
|
9074e80478 | ||
|
|
f7f43928cf | ||
|
|
1accb45f12 | ||
|
|
d9f53920e5 | ||
|
|
76d91332d7 | ||
|
|
728cbde683 | ||
|
|
60c98cd998 | ||
|
|
f1d106e0f0 | ||
|
|
c92194e90b | ||
|
|
91683af807 | ||
|
|
c5c898aa4e | ||
|
|
25634b2469 | ||
|
|
b8e764d09d | ||
|
|
17ed32857a | ||
|
|
d631d07e0f | ||
|
|
2ec4c69832 | ||
|
|
6426c965c6 | ||
|
|
4f6d410185 | ||
|
|
18a899f439 | ||
|
|
7e5b3fe233 | ||
|
|
4abd0eec6c | ||
|
|
cf17ed64c7 | ||
|
|
a2dd7c1e06 | ||
|
|
021fe66bec | ||
|
|
1b3896f4ca | ||
|
|
fc9ccf66d1 | ||
|
|
d205f2894b | ||
|
|
7afc04b2b2 | ||
|
|
584ee96ee0 | ||
|
|
66f7ea1b79 | ||
|
|
7b0a83458b | ||
|
|
cdaf7909d4 | ||
|
|
c70ab388c1 | ||
|
|
50c66c2703 | ||
|
|
357e520bb0 | ||
|
|
6379ce5741 | ||
|
|
02807739a1 | ||
|
|
40635ab75a | ||
|
|
32e1bfe6fd | ||
|
|
281a0e8499 | ||
|
|
220c61afe1 | ||
|
|
7a632d5224 | ||
|
|
3218c1a46b | ||
|
|
b2028d86ba | ||
|
|
45ed5879e6 | ||
|
|
48479dd064 | ||
|
|
3b556b81a1 | ||
|
|
526c9a607a | ||
|
|
81752895ab | ||
|
|
ad970d097a | ||
|
|
bc2010b49d | ||
|
|
ff4a4094ff | ||
|
|
3629e71098 | ||
|
|
b955ac355f | ||
|
|
409279eca0 | ||
|
|
ea0a0f1d93 | ||
|
|
3cc81dfddc | ||
|
|
86041e6031 | ||
|
|
e140ce2661 | ||
|
|
f6f15132a2 | ||
|
|
e73751ecf3 | ||
|
|
3c0516b4cd | ||
|
|
38d9f4a818 | ||
|
|
207fa4f2e7 | ||
|
|
f9f778b8f4 | ||
|
|
962dcdec67 | ||
|
|
486026b8aa | ||
|
|
e78d08fb94 | ||
|
|
a5e81dbd87 | ||
|
|
49051dae9a | ||
|
|
94236c87e3 | ||
|
|
449ba8c768 | ||
|
|
0da81c01e9 | ||
|
|
b4a0b7e1ea | ||
|
|
f2209eca49 | ||
|
|
4a004971c6 | ||
|
|
e400b8761c | ||
|
|
ff8e7b7f41 | ||
|
|
2c501606be | ||
|
|
73420fe1c4 | ||
|
|
337f81346c | ||
|
|
06f9a4545b | ||
|
|
fa99df93c4 | ||
|
|
adcd2472d5 | ||
|
|
7527b9a07e | ||
|
|
800c223baa | ||
|
|
d1123d3ccf | ||
|
|
f61fc99d9c | ||
|
|
60653cc739 | ||
|
|
d25bba10b0 | ||
|
|
3b67ecaa5e | ||
|
|
6600f32392 | ||
|
|
64303b1709 | ||
|
|
5c7e50d61e | ||
|
|
f68ad105a6 | ||
|
|
164479da1d | ||
|
|
d93bf41d28 | ||
|
|
38a2b3f2b2 | ||
|
|
342534676c | ||
|
|
56a6a6de03 | ||
|
|
d1445c2801 | ||
|
|
6d3ddede38 | ||
|
|
08dae9b342 | ||
|
|
13fab86b83 | ||
|
|
5ada5d74d2 | ||
|
|
aa1802c371 | ||
|
|
0cf1c6ecba | ||
|
|
f051420ff9 | ||
|
|
3902a40e30 | ||
|
|
0c97f15088 | ||
|
|
4cf112921b | ||
|
|
6e31b26af0 | ||
|
|
6f22b5dd03 | ||
|
|
9ee1bd0f79 | ||
|
|
56b11bc43c | ||
|
|
a476d490a6 | ||
|
|
74b50fb9c2 | ||
|
|
ddaedd0ba0 | ||
|
|
729342085a | ||
|
|
bb20178dc9 | ||
|
|
306cee1fd4 | ||
|
|
02e8732e9f |
@@ -21,10 +21,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Set up JDK 14
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '14'
|
||||
java-version: '17'
|
||||
distribution: 'adopt'
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
* Стабильные сборки находятся в [Releases](https://github.com/vtosters/lite/releases)
|
||||
|
||||
Зеркало на нашем [<img src="https://gitea.com/assets/img/logo.svg" align="center" width="20" height="20"/> Git](https://git.maki.su/gdlbo/lite)
|
||||
Зеркало на нашем [<img src="https://gitea.com/assets/img/logo.svg" align="center" width="20" height="20"/> Git](https://git.maki.su/vtosters/lite)
|
||||
|
||||
### Быстрая навигация
|
||||
|
||||
|
||||
+60
-71
@@ -1,8 +1,6 @@
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
@@ -21,6 +19,10 @@ 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()
|
||||
|
||||
versionFile {
|
||||
file = projectDir.toPath().resolve("src/main/assets/version.properties").toFile()
|
||||
@@ -50,19 +52,24 @@ android {
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
buildConfigField 'String', 'APPCENTER_KEY', '""'
|
||||
proguardFile 'proguard-rules.pro'
|
||||
}
|
||||
rc {
|
||||
minifyEnabled true
|
||||
buildConfigField 'String', 'APPCENTER_KEY', '""'
|
||||
proguardFile 'proguard-rules.pro'
|
||||
}
|
||||
dev {
|
||||
initWith release
|
||||
minifyEnabled false
|
||||
buildConfigField 'String', 'APPCENTER_KEY', '""'
|
||||
}
|
||||
beta {
|
||||
initWith release
|
||||
minifyEnabled false
|
||||
buildConfigField 'String', 'APPCENTER_KEY', '""'
|
||||
}
|
||||
release {
|
||||
buildConfigField 'String', 'APPCENTER_KEY', '""'
|
||||
minifyEnabled true
|
||||
proguardFile 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
@@ -72,6 +79,15 @@ android {
|
||||
}
|
||||
namespace 'ru.vtosters.lite'
|
||||
ndkVersion '25.2.9519653'
|
||||
buildFeatures {
|
||||
aidl true
|
||||
}
|
||||
}
|
||||
|
||||
task testClasses {
|
||||
doLast {
|
||||
println 'This is a dummy testClasses task'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -79,70 +95,44 @@ dependencies {
|
||||
implementation 'com.microsoft.appcenter:appcenter-crashes:5.0.1'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
|
||||
implementation 'net.sourceforge.streamsupport:streamsupport-minifuture:1.7.4'
|
||||
implementation 'com.google.guava:guava:23.3-android'
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.aar'])
|
||||
compileOnly fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'com.google.guava:guava:23.3-android'
|
||||
}
|
||||
|
||||
task generateBuildTasks() {
|
||||
android.applicationVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
def buildType = output.name.toString().capitalize()
|
||||
def lowerBuildType = buildType.toLowerCase()
|
||||
if(buildType=="Base")return
|
||||
task "exportDex$buildType"() {
|
||||
dependsOn('assemble' + buildType)
|
||||
doLast {
|
||||
try {
|
||||
var z = ""
|
||||
if (lowerBuildType != "debug") {
|
||||
z = "-unsigned"
|
||||
}
|
||||
|
||||
File moduleDir = projectDir
|
||||
ZipInputStream inputStream = new ZipInputStream(new FileInputStream(moduleDir.getAbsolutePath() + "/build/outputs/apk/$lowerBuildType/app-$lowerBuildType${z}.apk"))
|
||||
ZipFile file = new ZipFile(moduleDir.getAbsolutePath() + "/build/outputs/apk/$lowerBuildType/app-$lowerBuildType${z}.apk");
|
||||
ZipEntry entry
|
||||
while ((entry = inputStream.nextEntry) != null) {
|
||||
if (entry.getName().equals("classes.dex")) {
|
||||
print('classes.dex found!')
|
||||
|
||||
FileOutputStream outputStream = new FileOutputStream(new File(moduleDir.getAbsoluteFile(), "classes6.dex"))
|
||||
|
||||
byte[] buffer = new byte[1024]
|
||||
int len = 0
|
||||
while ((len = inputStream.read(buffer)) > 0) {
|
||||
outputStream.write(buffer, 0, len)
|
||||
}
|
||||
outputStream.close()
|
||||
}
|
||||
if (entry.getName().equals("classes2.dex")) {
|
||||
print('\nclasses2.dex found!')
|
||||
|
||||
FileOutputStream outputStream = new FileOutputStream(new File(moduleDir.getAbsoluteFile(), "classes7.dex"))
|
||||
|
||||
byte[] buffer = new byte[1024]
|
||||
int len = 0
|
||||
while ((len = inputStream.read(buffer)) > 0) {
|
||||
outputStream.write(buffer, 0, len)
|
||||
}
|
||||
outputStream.close()
|
||||
}
|
||||
}
|
||||
|
||||
for (ZipEntry e : Collections.list(file.entries())) {
|
||||
if (e.getName().endsWith("assets/version.properties")) {
|
||||
var is = file.getInputStream(e)
|
||||
FileOutputStream outputStream = new FileOutputStream(new File(moduleDir.getAbsoluteFile(), "version.properties"))
|
||||
|
||||
byte[] buffer = new byte[1024]
|
||||
int len = 0
|
||||
while ((len = is.read(buffer)) > 0) {
|
||||
outputStream.write(buffer, 0, len)
|
||||
}
|
||||
outputStream.close()
|
||||
|
||||
print('\nversion.properties found!')
|
||||
}
|
||||
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()
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace()
|
||||
@@ -152,17 +142,16 @@ task generateBuildTasks() {
|
||||
task "prepareDexForMerge$buildType"(type: Copy) {
|
||||
dependsOn('exportDex' + buildType)
|
||||
// Remove comment for native lib build
|
||||
dependsOn('cargoBuild')
|
||||
//dependsOn('cargoBuild')
|
||||
into smaliFolder.toString()
|
||||
from(projectDir) {
|
||||
include 'classes6.dex'
|
||||
include 'classes7.dex'
|
||||
into '../smali'
|
||||
include "classes*.dex"
|
||||
}
|
||||
from(projectDir) {
|
||||
include 'version.properties'
|
||||
into 'assets'
|
||||
}
|
||||
// Remove comment for native lib build
|
||||
from('../native-effects/target/aarch64-linux-android/release'){
|
||||
include 'libnative_effects.so'
|
||||
into 'lib/arm64-v8a'
|
||||
@@ -171,15 +160,16 @@ task generateBuildTasks() {
|
||||
include 'libnative_effects.so'
|
||||
into 'lib/armeabi-v7a'
|
||||
}
|
||||
doLast {
|
||||
new File(projectDir, "classes6.dex").delete()
|
||||
new File(projectDir, "classes7.dex").delete()
|
||||
new File(projectDir, "version.properties").delete()
|
||||
}
|
||||
}
|
||||
task "cleanTemporaryFiles$buildType"(type:Delete)
|
||||
{
|
||||
delete fileTree(dir:projectDir,include:["*.dex","version.properties"])
|
||||
delete fileTree(dir:smaliFolder,include:['*.dex',"assets/version.properties"])
|
||||
}
|
||||
task "buildVTL$buildType"(type: Exec) {
|
||||
dependsOn('prepareDexForMerge' + buildType)
|
||||
workingDir(projectDir.parentFile)
|
||||
finalizedBy "cleanTemporaryFiles$buildType"
|
||||
if (Os.isFamily("unix") || Os.isFamily("mac")) {
|
||||
commandLine 'bash', '-c', './scripts/build.sh'
|
||||
} else {
|
||||
@@ -207,7 +197,6 @@ task generateBuildTasks() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
task generateRjava(type: Exec) {
|
||||
workingDir(projectDir.parentFile)
|
||||
if (Os.isFamily("unix") || Os.isFamily("mac"))
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Vendored
+5
-2
@@ -32,13 +32,16 @@
|
||||
-repackageclasses
|
||||
-allowaccessmodification
|
||||
-optimizations
|
||||
-optimizationpasses 5
|
||||
-keepattributes SourceFile, LineNumberTable
|
||||
|
||||
-keep,allowoptimization class ru.vtosters.lite.** {
|
||||
-keep,allowoptimization class ru.vtosters.hooks.**, ru.vtosters.lite.utils.AndroidUtils, ru.vtosters.lite.utils.NetworkUtils, ru.vtosters.lite.utils.CrashReporter, ru.vtosters.lite.ui.activities.**, ru.vtosters.lite.services.**, ru.vtosters.lite.ui.fragments.**, ru.vtosters.lite.themes.**, ru.vtosters.lite.music.hook.**, ru.vtosters.lite.music.cache.injectors.**, ru.vtosters.lite.ui.wallpapers.NativeEffects, com.aefyr.tsg.g2.TelegramStickersService {
|
||||
public <fields>;
|
||||
public <methods>;
|
||||
public <init>(...);
|
||||
}
|
||||
|
||||
-keep class com.vtosters.lite.** { *; }
|
||||
-keep class com.vk.** { *; }
|
||||
-keep class bruhcollective.itaysonlab.libvkx.client.** { *; }
|
||||
-keep class bruhcollective.itaysonlab.libvkx.client.** { *; }
|
||||
-keep class com.guardanis.applock.** { *; }
|
||||
@@ -10,9 +10,9 @@ import com.vk.music.common.MusicPlaybackLaunchContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
import static ru.vtosters.hooks.other.Preferences.isValidSignature;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import static ru.vtosters.lite.utils.Preferences.isValidSignature;
|
||||
|
||||
public class LibVKXClient {
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
@@ -80,11 +80,6 @@ public class LibVKXClient {
|
||||
lambdaplay(list, musicTrack, iLibVkxService, null);
|
||||
}
|
||||
|
||||
public static String asId(MusicTrack musicTrack) {
|
||||
String id = musicTrack.e + "_" + musicTrack.d;
|
||||
if (musicTrack.O != null && !musicTrack.O.equals("")) {
|
||||
id += "_" + musicTrack.O;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
public static String asId(MusicTrack musicTrack)
|
||||
{ return musicTrack.y1(); }
|
||||
}
|
||||
@@ -36,10 +36,8 @@ public class TelegramStickersPack extends CustomStickersPack {
|
||||
public HashMap<String, List<Integer>> emojis = new HashMap<>();
|
||||
|
||||
public TelegramStickersPack(String id) {
|
||||
final var idLowerCase = id.toLowerCase();
|
||||
this.id = idLowerCase;
|
||||
this.hash = idLowerCase.hashCode();
|
||||
title = id;
|
||||
this.id=this.title=id;
|
||||
this.hash=id.hashCode();
|
||||
}
|
||||
|
||||
public JSONObject encodeEmojis() throws JSONException {
|
||||
@@ -103,7 +101,7 @@ public class TelegramStickersPack extends CustomStickersPack {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof TelegramStickersPack && ((TelegramStickersPack) obj).id.equalsIgnoreCase(id);
|
||||
return obj instanceof TelegramStickersPack && ((TelegramStickersPack) obj).id.equals(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.util.Log;
|
||||
import com.aefyr.tsg.g2.sql.TelegramStickersDbHelper;
|
||||
import com.aefyr.tsg.g2.stickersgrabber.TelegramStickersGrabber;
|
||||
import com.aefyr.tsg.g2.stickersgrabber.TelegramStickersPackInfo;
|
||||
import ru.vtosters.lite.ui.fragments.VTSettings;
|
||||
import ru.vtosters.lite.ui.fragments.tgstickers.StickersFragment;
|
||||
|
||||
import java.io.File;
|
||||
@@ -152,6 +153,7 @@ public class TelegramStickersService {
|
||||
|
||||
private void notifyActivePacksListChanged() {
|
||||
getGlobalContext().sendBroadcast(new Intent(StickersFragment.ACTION_RELOAD));
|
||||
getGlobalContext().sendBroadcast(new Intent(VTSettings.ACTION_INVALIDATE_TGS_COUNT));
|
||||
if (listeners.isEmpty())
|
||||
return;
|
||||
|
||||
@@ -222,7 +224,7 @@ public class TelegramStickersService {
|
||||
final TelegramStickersPack newPack = pack;
|
||||
final boolean isUpdate = update;
|
||||
|
||||
currentlyDownloading.add(id.toLowerCase());
|
||||
currentlyDownloading.add(id);
|
||||
notificationsHelper.packStartedDownloading(newPack);
|
||||
|
||||
|
||||
|
||||
@@ -130,9 +130,9 @@ public class BinaryResourceValue implements SerializableResource {
|
||||
*/
|
||||
public static final int SIZE = 8;
|
||||
|
||||
private final int size;
|
||||
private final Type type;
|
||||
private final int data;
|
||||
public int size;
|
||||
public Type type;
|
||||
public int data;
|
||||
|
||||
public static BinaryResourceValue create(ByteBuffer buffer) {
|
||||
int size = (buffer.getShort() & 0xFFFF);
|
||||
|
||||
@@ -0,0 +1,342 @@
|
||||
package com.guardanis.applock;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.hardware.fingerprint.FingerprintManagerCompat;
|
||||
import androidx.core.os.CancellationSignal;
|
||||
|
||||
import com.vtosters.lite.R;
|
||||
|
||||
import com.guardanis.applock.activities.UnlockActivity;
|
||||
import com.guardanis.applock.services.FingerprintLockService;
|
||||
import com.guardanis.applock.services.FingerprintLockService.AuthenticationDelegate;
|
||||
import com.guardanis.applock.services.LockService;
|
||||
import com.guardanis.applock.services.PINLockService;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class AppLock {
|
||||
|
||||
public static final int REQUEST_CODE_UNLOCK = 9371;
|
||||
public static final int REQUEST_CODE_LOCK_CREATION = 9372;
|
||||
public static final int REQUEST_CODE_FINGERPRINT_PERMISSION = 9373;
|
||||
public static final int ERROR_CODE_FINGERPRINTS_MISSING_HARDWARE = 1;
|
||||
public static final int ERROR_CODE_FINGERPRINTS_PERMISSION_REQUIRED = 2;
|
||||
public static final int ERROR_CODE_FINGERPRINTS_EMPTY = 3;
|
||||
public static final int ERROR_CODE_FINGERPRINTS_NOT_LOCALLY_ENROLLED = 4;
|
||||
public static final int ERROR_CODE_SDK_VERSION_MINIMUM = 5;
|
||||
private static final String PREFS = "pin__preferences";
|
||||
private static final String PREF_UNLOCK_FAILURE_TIME = "pin__unlock_failure_time";
|
||||
private static final String PREF_UNLOCK_SUCCESS_TIME = "pin__unlock_success_time";
|
||||
private static AppLock instance;
|
||||
protected Context context;
|
||||
protected HashMap<Class<? extends LockService>, LockService> lockServices = new HashMap<>();
|
||||
protected int unlockAttemptsCount = 1;
|
||||
|
||||
protected AppLock(Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
|
||||
this.lockServices.put(PINLockService.class, new PINLockService());
|
||||
this.lockServices.put(FingerprintLockService.class, new FingerprintLockService());
|
||||
}
|
||||
|
||||
public static AppLock getInstance(Context context) {
|
||||
if (instance == null)
|
||||
instance = new AppLock(context);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the user has enrolled in either PIN or Fingerprint locking
|
||||
*/
|
||||
public static boolean isEnrolled(Context context) {
|
||||
AppLock helper = getInstance(context);
|
||||
|
||||
for (LockService service : helper.lockServices.values()) {
|
||||
if (service.isEnrolled(context))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void setAuthenticationRequired(Context context) {
|
||||
AppLock helper = getInstance(context);
|
||||
|
||||
helper.getPreferences()
|
||||
.edit()
|
||||
.putLong(PREF_UNLOCK_SUCCESS_TIME, 0)
|
||||
.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the user is enrolled in locking and the last successful unlock happened more than the default lock duration ago
|
||||
*/
|
||||
public static boolean isUnlockRequired(Context context) {
|
||||
int minutes = Integer.parseInt(getPinCodeTime(context));
|
||||
|
||||
if (minutes < 1) {
|
||||
minutes = 1;
|
||||
}
|
||||
|
||||
return isUnlockRequired(context, TimeUnit.MINUTES.toMillis(minutes));
|
||||
}
|
||||
|
||||
public static String getPinCodeTime(Context context) {
|
||||
return context.getString(AndroidUtils.getIdentifier("applock__activity_lock_reenable_minutes", "integer"));
|
||||
}
|
||||
|
||||
public static String getPinCodeLimits(Context context) {
|
||||
return context.getString(AndroidUtils.getIdentifier("applock__input_pin_item_count", "integer"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the user is enrolled in locking and the last successful unlock happened more than lastSuccessValidMs ago
|
||||
*/
|
||||
public static boolean isUnlockRequired(Context context, long lastSuccessValidMs) {
|
||||
return isEnrolled(context) && lastSuccessValidMs < System.currentTimeMillis() - getUnlockSuccessTime(context);
|
||||
}
|
||||
|
||||
protected static long getUnlockSuccessTime(Context context) {
|
||||
return AppLock.getInstance(context)
|
||||
.getPreferences()
|
||||
.getLong(PREF_UNLOCK_SUCCESS_TIME, 0);
|
||||
}
|
||||
|
||||
public static void onActivityResumed(Activity activity) {
|
||||
if (isUnlockRequired(activity)) {
|
||||
boolean unlockActivityReturnAllowed = activity.getResources()
|
||||
.getBoolean(AndroidUtils.getIdentifier("applock__unlock_activity_return_allowed", "bool"));
|
||||
|
||||
Intent intent = new Intent(activity, UnlockActivity.class)
|
||||
.putExtra(UnlockActivity.INTENT_ALLOW_UNLOCKED_EXIT, unlockActivityReturnAllowed);
|
||||
|
||||
activity.startActivityForResult(intent, REQUEST_CODE_UNLOCK);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an action-based unlock is required and navigates to the UnlockActivity if true.
|
||||
*
|
||||
* @return true if unlock is required.
|
||||
*/
|
||||
public static boolean unlockIfRequired(Activity activity) {
|
||||
if (isUnlockRequired(activity)) {
|
||||
Intent intent = new Intent(activity, UnlockActivity.class)
|
||||
.putExtra(UnlockActivity.INTENT_ALLOW_UNLOCKED_EXIT, true);
|
||||
|
||||
activity.startActivityForResult(intent, REQUEST_CODE_UNLOCK);
|
||||
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
public void attemptFingerprintUnlock(final UnlockDelegate eventListener) {
|
||||
if (handleFailureBlocking(eventListener))
|
||||
return;
|
||||
|
||||
AuthenticationDelegate delegate = new AuthenticationDelegate() {
|
||||
@Override
|
||||
public void onResolutionRequired(int errorCode) {
|
||||
// eventListener.onResolutionRequired(errorCode);
|
||||
eventListener.requestOpenKeyboard();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationHelp(int code, CharSequence message) {
|
||||
eventListener.onAuthenticationHelp(code, String.valueOf(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticating(CancellationSignal cancellationSignal) {
|
||||
// Handled internally
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(@NonNull FingerprintManagerCompat.AuthenticationResult result) {
|
||||
onUnlockSuccessful(eventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed(String message) {
|
||||
Log.w(getClass().getSimpleName(), "Fingerprint authentication failed: " + message);
|
||||
}
|
||||
};
|
||||
|
||||
getLockService(FingerprintLockService.class)
|
||||
.authenticate(context, delegate);
|
||||
}
|
||||
|
||||
public void attemptPINUnlock(String pin, final UnlockDelegate eventListener) {
|
||||
if (handleFailureBlocking(eventListener))
|
||||
return;
|
||||
|
||||
PINLockService.AuthenticationDelegate delegate = new PINLockService.AuthenticationDelegate() {
|
||||
@Override
|
||||
public void onNoPIN() {
|
||||
onUnlockFailed(context.getString(AndroidUtils.getIdentifier("applock__unlock_error_no_matching_pin_found", "string")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPINDoesNotMatch() {
|
||||
onUnlockFailed(context.getString(AndroidUtils.getIdentifier("applock__unlock_error_match_failed", "string")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPINMatches() {
|
||||
onUnlockSuccessful(eventListener);
|
||||
}
|
||||
|
||||
private void onUnlockFailed(String message) {
|
||||
handleUnlockFailure(message, eventListener);
|
||||
}
|
||||
};
|
||||
|
||||
getLockService(PINLockService.class)
|
||||
.authenticate(context, pin, delegate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if failure blocking is enabled
|
||||
*/
|
||||
private boolean handleFailureBlocking(final UnlockDelegate eventListener) {
|
||||
if (isUnlockFailureBlockEnabled()) {
|
||||
unlockAttemptsCount++;
|
||||
|
||||
if (getFailureDelayMs() < System.currentTimeMillis() - getUnlockFailureBlockStart())
|
||||
resetUnlockFailure();
|
||||
else {
|
||||
String message = String.format(
|
||||
context.getString(AndroidUtils.getIdentifier("applock__unlock_error_retry_limit_exceeded", "string")),
|
||||
formatTimeRemaining());
|
||||
|
||||
if (eventListener != null)
|
||||
eventListener.onFailureLimitExceeded(message);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void handleUnlockFailure(String message, UnlockDelegate eventListener) {
|
||||
this.unlockAttemptsCount++;
|
||||
|
||||
if (eventListener != null)
|
||||
eventListener.onFailureLimitExceeded(message);
|
||||
|
||||
if (context.getResources().getInteger(AndroidUtils.getIdentifier("applock__max_retry_count", "integer")) < unlockAttemptsCount)
|
||||
onFailureExceedsLimit();
|
||||
}
|
||||
|
||||
public SharedPreferences getPreferences() {
|
||||
return context.getSharedPreferences(PREFS, 0);
|
||||
}
|
||||
|
||||
protected void onFailureExceedsLimit() {
|
||||
getPreferences()
|
||||
.edit()
|
||||
.putLong(PREF_UNLOCK_FAILURE_TIME, System.currentTimeMillis())
|
||||
.commit();
|
||||
}
|
||||
|
||||
public boolean isUnlockFailureBlockEnabled() {
|
||||
return context.getResources().getInteger(AndroidUtils.getIdentifier("applock__max_retry_count", "integer")) < unlockAttemptsCount
|
||||
|| System.currentTimeMillis() - getUnlockFailureBlockStart() < getFailureDelayMs();
|
||||
}
|
||||
|
||||
protected long getUnlockFailureBlockStart() {
|
||||
return getPreferences()
|
||||
.getLong(PREF_UNLOCK_FAILURE_TIME, 0);
|
||||
}
|
||||
|
||||
protected void onUnlockSuccessful(UnlockDelegate eventListener) {
|
||||
getPreferences()
|
||||
.edit()
|
||||
.putLong(PREF_UNLOCK_SUCCESS_TIME, System.currentTimeMillis())
|
||||
.commit();
|
||||
|
||||
resetUnlockFailure();
|
||||
|
||||
if (eventListener != null)
|
||||
eventListener.onUnlockSuccessful();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the last login time to require the user to re-authenticate with
|
||||
* AppLock the next time they are eligible to unlock.
|
||||
*/
|
||||
public void setAuthenticationRequired() {
|
||||
getPreferences()
|
||||
.edit()
|
||||
.putLong(PREF_UNLOCK_SUCCESS_TIME, 0)
|
||||
.commit();
|
||||
}
|
||||
|
||||
protected void resetUnlockFailure() {
|
||||
unlockAttemptsCount = 1;
|
||||
|
||||
getPreferences()
|
||||
.edit()
|
||||
.putLong(PREF_UNLOCK_FAILURE_TIME, 0)
|
||||
.commit();
|
||||
}
|
||||
|
||||
protected String formatTimeRemaining() {
|
||||
long millis = getFailureDelayMs() - (System.currentTimeMillis() - getUnlockFailureBlockStart());
|
||||
long seconds = TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis));
|
||||
|
||||
if (TimeUnit.MILLISECONDS.toMinutes(millis) < 1)
|
||||
return String.format(AndroidUtils.getString(R.string.n_seconds), seconds);
|
||||
else
|
||||
return String.format(AndroidUtils.getString(R.string.n_mins_secs), TimeUnit.MILLISECONDS.toMinutes(millis), seconds);
|
||||
}
|
||||
|
||||
protected long getFailureDelayMs() {
|
||||
return TimeUnit.MINUTES.toMillis(context.getResources()
|
||||
.getInteger(AndroidUtils.getIdentifier("applock__failure_retry_delay", "integer")));
|
||||
}
|
||||
|
||||
/**
|
||||
* This will remove all PIN and/or Fingerprint enrollment data.
|
||||
* Users will need to re-enroll in AppLock after this call.
|
||||
*/
|
||||
public void invalidateEnrollments() {
|
||||
resetUnlockFailure();
|
||||
setAuthenticationRequired();
|
||||
|
||||
for (LockService service : lockServices.values())
|
||||
service.invalidateEnrollments(context);
|
||||
}
|
||||
|
||||
public void cancelPendingAuthentications() {
|
||||
for (LockService service : lockServices.values())
|
||||
service.cancelPendingAuthentications(context);
|
||||
}
|
||||
|
||||
public <T extends LockService> T getLockService(Class<T> named) {
|
||||
return (T) lockServices.get(named);
|
||||
}
|
||||
|
||||
public interface UnlockDelegate {
|
||||
void onUnlockSuccessful();
|
||||
|
||||
void onResolutionRequired(int errorCode);
|
||||
|
||||
void onAuthenticationHelp(int code, String message);
|
||||
|
||||
void onFailureLimitExceeded(String message);
|
||||
void requestOpenKeyboard();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.guardanis.applock.activities;
|
||||
|
||||
import static ru.vtosters.hooks.other.ThemesUtils.getBackgroundContent;
|
||||
import static ru.vtosters.hooks.other.ThemesUtils.getTextAttr;
|
||||
import static ru.vtosters.hooks.other.ThemesUtils.isDarkTheme;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getIdentifier;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsetsController;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.guardanis.applock.views.LockCreationViewController;
|
||||
|
||||
|
||||
public class LockCreationActivity extends AppCompatActivity implements LockCreationViewController.Delegate {
|
||||
|
||||
protected LockCreationViewController viewController;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstance) {
|
||||
super.onCreate(savedInstance);
|
||||
|
||||
setContentView(getIdentifier("applock__activity_lock_creation", "layout"));
|
||||
findViewById(getIdentifier("applock__activity_lock_creation", "id")).setBackgroundColor(getBackgroundContent());
|
||||
((TextView) findViewById(getIdentifier("pin__description", "id"))).setTextColor(getTextAttr());
|
||||
|
||||
this.viewController = new LockCreationViewController(this, findViewById(getIdentifier("pin__container", "id")));
|
||||
this.viewController.setDelegate(this);
|
||||
this.viewController.setupRootFlow();
|
||||
|
||||
this.getWindow().setStatusBarColor(getBackgroundContent());
|
||||
this.getWindow().setNavigationBarColor(getBackgroundContent());
|
||||
|
||||
if (!isDarkTheme()) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
this.getWindow().getInsetsController().setSystemBarsAppearance(WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS);
|
||||
} else {
|
||||
this.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLockCreated() {
|
||||
setResult(Activity.RESULT_OK);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPointerCaptureChanged(boolean hasCapture) {
|
||||
super.onPointerCaptureChanged(hasCapture);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.guardanis.applock.activities;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.guardanis.applock.AppLock;
|
||||
|
||||
public class LockableAppCompatActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onPostResume() {
|
||||
super.onPostResume();
|
||||
|
||||
AppLock.onActivityResumed(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (requestCode == AppLock.REQUEST_CODE_UNLOCK && resultCode == Activity.RESULT_CANCELED)
|
||||
handleUnlockActivityReturnFailure();
|
||||
}
|
||||
|
||||
protected void handleUnlockActivityReturnFailure() {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.guardanis.applock.activities;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsetsController;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.guardanis.applock.views.UnlockViewController;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import static ru.vtosters.hooks.other.ThemesUtils.getBackgroundContent;
|
||||
import static ru.vtosters.hooks.other.ThemesUtils.getTextAttr;
|
||||
import static ru.vtosters.hooks.other.ThemesUtils.isDarkTheme;
|
||||
|
||||
public class UnlockActivity extends AppCompatActivity implements UnlockViewController.Delegate {
|
||||
|
||||
public static final String INTENT_ALLOW_UNLOCKED_EXIT = "pin__allow_activity_exit"; // false by default
|
||||
|
||||
protected UnlockViewController viewController;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstance) {
|
||||
super.onCreate(savedInstance);
|
||||
|
||||
setContentView(AndroidUtils.getIdentifier("applock__activity_unlock", "layout"));
|
||||
findViewById(AndroidUtils.getIdentifier("applock__activity_unlock", "id")).setBackgroundColor(getBackgroundContent());
|
||||
((TextView) findViewById(AndroidUtils.getIdentifier("pin__description", "id"))).setTextColor(getTextAttr());
|
||||
|
||||
this.viewController = new UnlockViewController(this, findViewById(AndroidUtils.getIdentifier("pin__container", "id")));
|
||||
this.viewController.setAutoAuthorizationEnabled(false); // Disable auto authorization so fingerprint doesn't crash onResume
|
||||
this.viewController.setDelegate(this);
|
||||
this.viewController.setupRootFlow();
|
||||
this.viewController.setAutoAuthorizationEnabled(true);
|
||||
|
||||
this.getWindow().setStatusBarColor(getBackgroundContent());
|
||||
this.getWindow().setNavigationBarColor(getBackgroundContent());
|
||||
|
||||
if (!isDarkTheme()) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
this.getWindow().getInsetsController().setSystemBarsAppearance(WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS);
|
||||
} else {
|
||||
this.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnlockSuccessful() {
|
||||
setResult(Activity.RESULT_OK);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
if (event.getRepeatCount() == 0) handleBackPressed();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
handleBackPressed();
|
||||
}
|
||||
|
||||
protected void handleBackPressed() {
|
||||
if (!getIntent().getBooleanExtra(INTENT_ALLOW_UNLOCKED_EXIT, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPointerCaptureChanged(boolean hasCapture) {
|
||||
super.onPointerCaptureChanged(hasCapture);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.guardanis.applock.dialogs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatDialog;
|
||||
|
||||
import com.guardanis.applock.AppLock;
|
||||
import com.guardanis.applock.views.AppLockViewController;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public abstract class AppLockDialogBuilder<ALVC extends AppLockViewController> {
|
||||
|
||||
protected WeakReference<Activity> activity;
|
||||
protected ALVC viewController;
|
||||
|
||||
protected WeakReference<AppCompatDialog> dialog = new WeakReference<AppCompatDialog>(null);
|
||||
protected int layoutResId;
|
||||
|
||||
public AppLockDialogBuilder(Activity activity, int layoutResId) {
|
||||
this.activity = new WeakReference<>(activity);
|
||||
this.layoutResId = layoutResId;
|
||||
}
|
||||
|
||||
public Dialog show() {
|
||||
if (viewController != null)
|
||||
throw new RuntimeException("You can only call show() once per AppLockDialogBuilder instance.");
|
||||
|
||||
final Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null)
|
||||
return null;
|
||||
|
||||
View parent = activity.getLayoutInflater()
|
||||
.inflate(layoutResId, null, false);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setView(parent);
|
||||
builder.setOnCancelListener(dialogInterface -> handleCanceled());
|
||||
builder.setOnDismissListener(dialogInterface -> handleDismissed());
|
||||
|
||||
this.viewController = buildViewControllerInstance(parent);
|
||||
this.viewController.setupRootFlow();
|
||||
|
||||
AppCompatDialog dialog = builder.show();
|
||||
|
||||
this.dialog = new WeakReference<>(dialog);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
protected abstract ALVC buildViewControllerInstance(View parent);
|
||||
|
||||
protected void handleCanceled() {
|
||||
dismissDialog();
|
||||
}
|
||||
|
||||
protected void handleDismissed() {
|
||||
this.dialog = new WeakReference<>(null);
|
||||
this.viewController.unregisterReceivers();
|
||||
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null)
|
||||
return;
|
||||
|
||||
AppLock.getInstance(activity)
|
||||
.cancelPendingAuthentications();
|
||||
}
|
||||
|
||||
protected void dismissDialog() {
|
||||
try {
|
||||
AppCompatDialog dialog = this.dialog.get();
|
||||
|
||||
if (dialog == null)
|
||||
return;
|
||||
|
||||
// Attempt to prevent stupid fucking uncatchable system error "View not Attached to Window" when dialog dismissed
|
||||
Context context = ((ContextWrapper) dialog.getContext()).getBaseContext();
|
||||
if (context instanceof Activity) {
|
||||
if (!((Activity) context).isFinishing()) {
|
||||
if (!((Activity) context).isDestroyed())
|
||||
dialog.dismiss();
|
||||
}
|
||||
} else
|
||||
dialog.dismiss();
|
||||
} catch (Throwable e) {
|
||||
Log.e("AppLockDialogBuilder", "View not Attached to Window???", e);
|
||||
}
|
||||
|
||||
this.dialog = new WeakReference<>(null);
|
||||
}
|
||||
|
||||
public ALVC getViewController() {
|
||||
return viewController;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.guardanis.applock.dialogs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.view.View;
|
||||
|
||||
import com.guardanis.applock.views.LockCreationViewController;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class LockCreationDialogBuilder extends AppLockDialogBuilder<LockCreationViewController> implements LockCreationViewController.Delegate {
|
||||
|
||||
protected Runnable lockCreatedCallback;
|
||||
protected Runnable canceledCallback;
|
||||
|
||||
public LockCreationDialogBuilder(Activity activity) {
|
||||
super(activity, AndroidUtils.getIdentifier("applock__lock_creation", "layout"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Runnable to be triggered when a user has successfully enrolled in locking.
|
||||
*/
|
||||
public LockCreationDialogBuilder onLockCreated(Runnable lockCreatedCallback) {
|
||||
this.lockCreatedCallback = lockCreatedCallback;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Runnable to be triggered when a user has canceled enrollment.
|
||||
*/
|
||||
public LockCreationDialogBuilder onCanceled(Runnable canceledCallback) {
|
||||
this.canceledCallback = canceledCallback;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LockCreationViewController buildViewControllerInstance(View parent) {
|
||||
LockCreationViewController controller = new LockCreationViewController(activity.get(), parent);
|
||||
controller.setDelegate(this);
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLockCreated() {
|
||||
dismissDialog();
|
||||
|
||||
if (lockCreatedCallback != null)
|
||||
lockCreatedCallback.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleCanceled() {
|
||||
super.handleCanceled();
|
||||
|
||||
if (canceledCallback != null)
|
||||
canceledCallback.run();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.guardanis.applock.dialogs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.view.View;
|
||||
|
||||
import com.guardanis.applock.AppLock;
|
||||
import com.guardanis.applock.views.UnlockViewController;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class UnlockDialogBuilder extends AppLockDialogBuilder<UnlockViewController> implements UnlockViewController.Delegate {
|
||||
|
||||
protected Runnable unlockCallback;
|
||||
protected Runnable canceledCallback;
|
||||
|
||||
public UnlockDialogBuilder(Activity activity) {
|
||||
super(activity, AndroidUtils.getIdentifier("applock__unlock", "layout"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Runnable to be triggered when a user has successfully unlocked.
|
||||
*/
|
||||
public UnlockDialogBuilder onUnlocked(Runnable unlockCallback) {
|
||||
this.unlockCallback = unlockCallback;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Runnable to be triggered when a user has canceled unlocking.
|
||||
*/
|
||||
public UnlockDialogBuilder onCanceled(Runnable canceledCallback) {
|
||||
this.canceledCallback = canceledCallback;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UnlockViewController buildViewControllerInstance(View parent) {
|
||||
UnlockViewController controller = new UnlockViewController(activity.get(), parent);
|
||||
controller.setDelegate(this);
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnlockSuccessful() {
|
||||
dismissDialog();
|
||||
triggerUnlockCallback();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleCanceled() {
|
||||
super.handleCanceled();
|
||||
|
||||
if (canceledCallback != null)
|
||||
canceledCallback.run();
|
||||
}
|
||||
|
||||
protected void triggerUnlockCallback() {
|
||||
if (unlockCallback != null)
|
||||
unlockCallback.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user is actually enrolled in locking before opening the unlock dialog.
|
||||
* If the user is enrolled, show() will be called. Otherwise, this function will trigger this
|
||||
* instance's UnlockDialogBuilder.unlockCallback immediately.
|
||||
*
|
||||
* @return Dialog if show() is called
|
||||
*/
|
||||
public Dialog showIfEnrolledOrSuccess() {
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null)
|
||||
return null;
|
||||
|
||||
if (!AppLock.isEnrolled(activity)) {
|
||||
triggerUnlockCallback();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user is both enrolled in locking and that unlocking is required before
|
||||
* opening the unlock dialog. If the user is enrolled, show() will be called. Otherwise,
|
||||
* this function will trigger this instance's UnlockDialogBuilder.unlockCallback immediately.
|
||||
*
|
||||
* @param longValidDurationMs the milliseconds a user's last unlock is valid for
|
||||
* @return Dialog if show() is called
|
||||
*/
|
||||
public Dialog showIfRequiredOrSuccess(long longValidDurationMs) {
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null)
|
||||
return null;
|
||||
|
||||
if (!AppLock.isUnlockRequired(activity, longValidDurationMs)) {
|
||||
triggerUnlockCallback();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.guardanis.applock.pin;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.TextView;
|
||||
import com.guardanis.applock.AppLock;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
interface InputTextListener {
|
||||
void onTextEntered(int count);
|
||||
}
|
||||
|
||||
public class PINInputController implements TextView.OnEditorActionListener, InputTextListener {
|
||||
|
||||
private final WeakReference<PINInputView> inputView;
|
||||
private WeakReference<InputEventListener> eventListener = new WeakReference<>(null);
|
||||
|
||||
/**
|
||||
* If you want to actually receive events after this, make sure you call setInputEventListener
|
||||
*/
|
||||
public PINInputController(PINInputView inputView) {
|
||||
this.inputView = new WeakReference<>(inputView);
|
||||
|
||||
inputView.setOnEditorActionListener(this);
|
||||
inputView.setInputTextListener(this);
|
||||
}
|
||||
|
||||
public PINInputController ensureKeyboardVisible() {
|
||||
final PINInputView inputView = this.inputView.get();
|
||||
|
||||
if (inputView == null)
|
||||
return this;
|
||||
|
||||
inputView.postDelayed(inputView::ensureKeyboardVisible, 300);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public PINInputController setPasswordCharactersEnabled(boolean passwordCharacterEnabled) {
|
||||
this.inputView.get().setPasswordCharactersEnabled(passwordCharacterEnabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PINInputController setInputNumbersCount(int inputNumbersCount) {
|
||||
this.inputView.get().setInputViewsCount(inputNumbersCount);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PINInputController setInputEventListener(InputEventListener eventListener) {
|
||||
this.eventListener = new WeakReference<>(eventListener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) {
|
||||
PINInputView inputView = this.inputView.get();
|
||||
|
||||
if (inputView == null)
|
||||
return false;
|
||||
|
||||
if (isSoftKeyboardFinishedAction(textView, i, keyEvent)) {
|
||||
InputEventListener eventListener = this.eventListener.get();
|
||||
|
||||
if (eventListener != null)
|
||||
eventListener.onInputEntered(inputView.getText());
|
||||
|
||||
inputView.reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isSoftKeyboardFinishedAction(TextView view, int action, KeyEvent event) {
|
||||
// Some devices return null event on editor actions for Enter Button (thanks, Samsung)
|
||||
if (!(event == null || event.getAction() == KeyEvent.ACTION_DOWN))
|
||||
return false;
|
||||
|
||||
// Enter clicked on Bluetooth Keyboard (action is zero on hardware keyboards)
|
||||
if (action == EditorInfo.IME_ACTION_UNSPECIFIED && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)
|
||||
return true;
|
||||
|
||||
return action == EditorInfo.IME_ACTION_DONE
|
||||
|| action == EditorInfo.IME_ACTION_GO
|
||||
|| action == EditorInfo.IME_ACTION_SEND;
|
||||
}
|
||||
|
||||
public boolean matchesRequiredPINLength(String input) {
|
||||
final PINInputView inputView = this.inputView.get();
|
||||
|
||||
if (inputView == null)
|
||||
return false;
|
||||
|
||||
return inputView.matchesRequiredPINLength(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextEntered(int count) {
|
||||
if (count == Integer.parseInt(AppLock.getPinCodeLimits(AndroidUtils.getGlobalContext()))) {
|
||||
var inputView = this.inputView.get();
|
||||
InputEventListener eventListener = this.eventListener.get();
|
||||
|
||||
if (eventListener != null)
|
||||
eventListener.onInputEntered(inputView.getText());
|
||||
|
||||
inputView.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public interface InputEventListener {
|
||||
void onInputEntered(String input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
package com.guardanis.applock.pin;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import com.guardanis.applock.AppLock;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class PINInputView extends LinearLayout implements TextWatcher {
|
||||
|
||||
private final WeakHashMap<PINItemView, PINItemAnimator> animators = new WeakHashMap<PINItemView, PINItemAnimator>();
|
||||
private Paint itemTextPaint;
|
||||
private Paint itemBackgroundPaint;
|
||||
private int inputViewsCount = 10;
|
||||
private PINItemView[] pinItemViews;
|
||||
private EditText editText;
|
||||
private String lastText = "";
|
||||
private boolean passwordCharactersEnabled = true;
|
||||
private String passwordCharacter;
|
||||
private InputTextListener listener;
|
||||
|
||||
|
||||
public PINInputView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
init(attrs);
|
||||
}
|
||||
|
||||
private void init(AttributeSet attrs) {
|
||||
setWillNotDraw(false);
|
||||
setupEditText();
|
||||
|
||||
|
||||
itemTextPaint = new Paint();
|
||||
itemTextPaint.setColor(ThemesUtils.getAccentColor());
|
||||
|
||||
itemBackgroundPaint = new Paint();
|
||||
itemBackgroundPaint.setColor(ThemesUtils.getMutedAccentColor());
|
||||
|
||||
|
||||
inputViewsCount = Integer.parseInt(AppLock.getPinCodeLimits(AndroidUtils.getGlobalContext()));
|
||||
|
||||
passwordCharacter = getResources().getString(AndroidUtils.getIdentifier("applock__password_char", "string"));
|
||||
|
||||
}
|
||||
|
||||
protected void setupEditText() {
|
||||
removeAllViews();
|
||||
|
||||
this.editText = inflateFakeEditText();
|
||||
this.editText.addTextChangedListener(this);
|
||||
|
||||
addView(editText);
|
||||
}
|
||||
|
||||
protected EditText inflateFakeEditText() {
|
||||
return (EditText) LayoutInflater.from(getContext())
|
||||
.inflate(AndroidUtils.getIdentifier("applock__fake_edit_text", "layout"), this, false);
|
||||
}
|
||||
|
||||
public PINInputView setInputViewsCount(int inputViewsCount) {
|
||||
this.inputViewsCount = inputViewsCount;
|
||||
|
||||
return reset();
|
||||
}
|
||||
|
||||
public PINInputView reset() {
|
||||
this.lastText = "";
|
||||
this.editText.setText("");
|
||||
|
||||
if (pinItemViews != null)
|
||||
animateLastOut();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
ensureKeyboardVisible();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
public void ensureKeyboardVisible() {
|
||||
editText.requestFocus();
|
||||
|
||||
((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE))
|
||||
.showSoftInput(editText, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas) {
|
||||
if (pinItemViews == null || pinItemViews.length != inputViewsCount)
|
||||
setupItemViews(canvas);
|
||||
|
||||
String text = editText.getText().toString();
|
||||
|
||||
for (int i = 0; i < pinItemViews.length; i++) {
|
||||
String textItem = i < text.length()
|
||||
? (passwordCharactersEnabled ? passwordCharacter : text.substring(i, i + 1))
|
||||
: "";
|
||||
|
||||
pinItemViews[i].draw(canvas, textItem);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupItemViews(Canvas canvas) {
|
||||
pinItemViews = new PINItemView[inputViewsCount];
|
||||
|
||||
int cellWidth = canvas.getWidth() / inputViewsCount;
|
||||
int largestRadius = Math.min(cellWidth / 2, canvas.getHeight() / 2);
|
||||
int smallestRadius = (int) (largestRadius * Float.parseFloat(getResources().getString(AndroidUtils.getIdentifier("applock__empty_item_min_size_percent", "string"))));
|
||||
int[] minMaxRadius = new int[]{smallestRadius, largestRadius};
|
||||
|
||||
itemTextPaint.setTextSize((int) (largestRadius * .85));
|
||||
|
||||
for (int i = 0; i < pinItemViews.length; i++) {
|
||||
float[] positionInCanvas = getPositionInCanvas(canvas, i, cellWidth);
|
||||
|
||||
pinItemViews[i] = new PINItemView(positionInCanvas, minMaxRadius, itemTextPaint, itemBackgroundPaint);
|
||||
}
|
||||
}
|
||||
|
||||
private float[] getPositionInCanvas(Canvas canvas, int position, int cellWidth) {
|
||||
return new float[]{
|
||||
(cellWidth * position) + (cellWidth / 2),
|
||||
canvas.getHeight() / 2
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
if (editable == null || lastText == null)
|
||||
return;
|
||||
|
||||
String text = editable.toString();
|
||||
if (inputViewsCount < text.length()) {
|
||||
editText.setText(lastText);
|
||||
editText.setSelection(editText.getText().length());
|
||||
} else if (text.length() < lastText.length()) {
|
||||
animateLastOut();
|
||||
this.lastText = text;
|
||||
} else if (lastText.length() < text.length()) {
|
||||
animateLastIn();
|
||||
this.lastText = text;
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onTextEntered(text.length());
|
||||
}
|
||||
}
|
||||
|
||||
public void setInputTextListener(InputTextListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
private void animateLastOut() {
|
||||
int startingIndex = editText.getText().toString().length(); // One after current length, only happens on backspace
|
||||
|
||||
for (int i = pinItemViews.length - 1; startingIndex <= i; i--)
|
||||
if (!pinItemViews[i].isAnimatedOut())
|
||||
animate(pinItemViews[i], PINItemAnimator.ItemAnimationDirection.OUT);
|
||||
}
|
||||
|
||||
private void animateLastIn() {
|
||||
PINItemView item = pinItemViews[editText.getText().toString().length() - 1];
|
||||
animate(item, PINItemAnimator.ItemAnimationDirection.IN);
|
||||
}
|
||||
|
||||
private void animate(PINItemView view, PINItemAnimator.ItemAnimationDirection direction) {
|
||||
cancelPreviousAnimation(view);
|
||||
view.setAnimationDirection(direction);
|
||||
|
||||
PINItemAnimator animator = new PINItemAnimator(this, view, direction);
|
||||
animators.put(view, animator);
|
||||
animator.start();
|
||||
}
|
||||
|
||||
private void cancelPreviousAnimation(PINItemView view) {
|
||||
PINItemAnimator animator = animators.get(view);
|
||||
|
||||
try {
|
||||
animator.cancel();
|
||||
animators.put(view, null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return editText.getText().toString();
|
||||
}
|
||||
|
||||
public void setOnEditorActionListener(TextView.OnEditorActionListener actionListener) {
|
||||
editText.setOnEditorActionListener(actionListener);
|
||||
}
|
||||
|
||||
public void setPasswordCharactersEnabled(boolean passwordCharactersEnabled) {
|
||||
this.passwordCharactersEnabled = passwordCharactersEnabled;
|
||||
}
|
||||
|
||||
public void setPasswordCharacter(String passwordCharacter) {
|
||||
this.passwordCharacter = passwordCharacter;
|
||||
}
|
||||
|
||||
public boolean matchesRequiredPINLength(String input) {
|
||||
return input.length() == inputViewsCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.guardanis.applock.pin;
|
||||
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class PINItemAnimator extends Thread {
|
||||
|
||||
private static final int ANIMATION_DURATION = 150;
|
||||
private static final int UPDATE_RATE = 25;
|
||||
private final WeakReference<PINInputView> inputView;
|
||||
private final PINItemView itemView;
|
||||
private final ItemAnimationDirection animationDirection;
|
||||
private final Interpolator itemInterpolator = new AccelerateDecelerateInterpolator();
|
||||
private final float minSizePercent;
|
||||
private long startTime;
|
||||
private boolean canceled = false;
|
||||
|
||||
public PINItemAnimator(PINInputView inputView, PINItemView itemView, ItemAnimationDirection animationDirection) {
|
||||
this.inputView = new WeakReference<>(inputView);
|
||||
this.itemView = itemView;
|
||||
this.animationDirection = animationDirection;
|
||||
this.minSizePercent = Float.parseFloat(inputView.getResources().getString(AndroidUtils.getIdentifier("applock__empty_item_min_size_percent", "string")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
this.startTime = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
if (animationDirection == ItemAnimationDirection.IN)
|
||||
animateIn();
|
||||
else
|
||||
animateOut();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void animateIn() throws Exception {
|
||||
float percent = minSizePercent;
|
||||
|
||||
while (percent < 1 && !canceled) {
|
||||
percent = Math.min(minSizePercent + calculatePercentComplete(), 1);
|
||||
updateView(percent);
|
||||
|
||||
Thread.sleep(UPDATE_RATE);
|
||||
}
|
||||
}
|
||||
|
||||
private void animateOut() throws Exception {
|
||||
float percent = 1 - calculatePercentComplete();
|
||||
|
||||
while (minSizePercent < percent && !canceled) {
|
||||
percent = Math.max(1 - calculatePercentComplete(), minSizePercent);
|
||||
updateView(percent);
|
||||
|
||||
Thread.sleep(UPDATE_RATE);
|
||||
}
|
||||
}
|
||||
|
||||
protected float calculatePercentComplete() {
|
||||
float completed = ((float) (System.currentTimeMillis() - startTime)) / ANIMATION_DURATION;
|
||||
|
||||
return itemInterpolator.getInterpolation(completed);
|
||||
}
|
||||
|
||||
private void updateView(final float percent) {
|
||||
final PINInputView inputView = this.inputView.get();
|
||||
|
||||
if (inputView == null)
|
||||
return;
|
||||
|
||||
inputView.post(() -> {
|
||||
itemView.onAnimationUpdate(percent);
|
||||
|
||||
inputView.invalidate();
|
||||
});
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
this.canceled = true;
|
||||
}
|
||||
|
||||
public enum ItemAnimationDirection {
|
||||
IN, OUT
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.guardanis.applock.pin;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
|
||||
public class PINItemView {
|
||||
|
||||
private final float[] position;
|
||||
private final int intendedRadius;
|
||||
private int currentRadius;
|
||||
private Paint backgroundPaint;
|
||||
|
||||
private float[] textPosition;
|
||||
private Paint textPaint;
|
||||
|
||||
private PINItemAnimator.ItemAnimationDirection animationDirection = PINItemAnimator.ItemAnimationDirection.IN;
|
||||
|
||||
public PINItemView(float[] position, int[] minMaxRadius, Paint baseTextPaint, Paint baseBackgroundPaint) {
|
||||
this.position = position;
|
||||
this.intendedRadius = minMaxRadius[1];
|
||||
this.currentRadius = minMaxRadius[0];
|
||||
|
||||
setupPaints(baseTextPaint, baseBackgroundPaint);
|
||||
}
|
||||
|
||||
private void setupPaints(Paint baseTextPaint, Paint baseBackgroundPaint) {
|
||||
this.textPaint = new Paint();
|
||||
this.textPaint.setTextAlign(Paint.Align.CENTER);
|
||||
this.textPaint.setAntiAlias(true);
|
||||
this.textPaint.setColor(baseTextPaint.getColor());
|
||||
this.textPaint.setTextSize(baseTextPaint.getTextSize());
|
||||
|
||||
this.textPosition = new float[]{
|
||||
position[0],
|
||||
position[1] - ((textPaint.descent() + textPaint.ascent()) / 2)
|
||||
};
|
||||
|
||||
this.backgroundPaint = new Paint();
|
||||
this.backgroundPaint.setTextAlign(Paint.Align.CENTER);
|
||||
this.backgroundPaint.setAntiAlias(true);
|
||||
this.backgroundPaint.setColor(baseBackgroundPaint.getColor());
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas, String textValue) {
|
||||
canvas.drawCircle(position[0], position[1], currentRadius, backgroundPaint);
|
||||
canvas.drawText(textValue, textPosition[0], textPosition[1], textPaint);
|
||||
}
|
||||
|
||||
public void setAnimationDirection(PINItemAnimator.ItemAnimationDirection animationDirection) {
|
||||
this.animationDirection = animationDirection;
|
||||
}
|
||||
|
||||
public void onAnimationUpdate(float percentCompleted) {
|
||||
this.currentRadius = (int) (intendedRadius * percentCompleted);
|
||||
this.textPaint.setAlpha((int) (255 * percentCompleted));
|
||||
}
|
||||
|
||||
public boolean isAnimatedOut() {
|
||||
return animationDirection == PINItemAnimator.ItemAnimationDirection.OUT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
package com.guardanis.applock.services;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.hardware.fingerprint.FingerprintManagerCompat;
|
||||
import androidx.core.os.CancellationSignal;
|
||||
|
||||
import com.guardanis.applock.AppLock;
|
||||
import com.guardanis.applock.utils.CipherGenerator;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class FingerprintLockService extends LockService {
|
||||
|
||||
private static final String PREF_ENROLLMENT_ALLOWED = "pin__fingerprint_enrollment_allowed";
|
||||
protected CancellationSignal fingerprintCancellationSignal;
|
||||
|
||||
@Override
|
||||
public boolean isEnrollmentEligible(Context context) {
|
||||
return Build.VERSION_CODES.M <= Build.VERSION.SDK_INT && context.getResources().getBoolean(AndroidUtils.getIdentifier("applock__fingerprint_service_enabled", "bool")) && isHardwarePresent(context);
|
||||
}
|
||||
|
||||
public void enroll(Context context, AuthenticationDelegate delegate) {
|
||||
authenticate(context, false, delegate);
|
||||
}
|
||||
|
||||
public void authenticate(Context context, AuthenticationDelegate delegate) {
|
||||
authenticate(context, true, delegate);
|
||||
}
|
||||
|
||||
protected void authenticate(Context context, boolean localEnrollmentRequired, AuthenticationDelegate delegate) {
|
||||
int errorCode = getRequiredResolutionErrorCode(context, localEnrollmentRequired);
|
||||
|
||||
if (-1 < errorCode) {
|
||||
delegate.onResolutionRequired(errorCode);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Should be handled by getRequiredResolutionErrorCode(Context, boolean)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return;
|
||||
|
||||
attemptFingerprintManagerAuthentication(context, delegate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the resolvable error code or -1 if there are no issues requiring a resolution
|
||||
*/
|
||||
protected int getRequiredResolutionErrorCode(Context context, boolean localEnrollmentRequired) {
|
||||
FingerprintManagerCompat manager = FingerprintManagerCompat.from(context);
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
|
||||
return AppLock.ERROR_CODE_SDK_VERSION_MINIMUM;
|
||||
|
||||
if (localEnrollmentRequired && !isEnrolled(context))
|
||||
return AppLock.ERROR_CODE_FINGERPRINTS_NOT_LOCALLY_ENROLLED;
|
||||
|
||||
if (!isHardwarePresent(context)) return AppLock.ERROR_CODE_FINGERPRINTS_MISSING_HARDWARE;
|
||||
|
||||
if (!manager.hasEnrolledFingerprints()) return AppLock.ERROR_CODE_FINGERPRINTS_EMPTY;
|
||||
|
||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED)
|
||||
return AppLock.ERROR_CODE_FINGERPRINTS_PERMISSION_REQUIRED;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected void attemptFingerprintManagerAuthentication(final Context context, final AuthenticationDelegate delegate) {
|
||||
this.fingerprintCancellationSignal = new CancellationSignal();
|
||||
|
||||
|
||||
var callback = new FingerprintManagerCompat.AuthenticationCallback() {
|
||||
@Override
|
||||
public void onAuthenticationError(int errMsgId, CharSequence errString) {
|
||||
super.onAuthenticationError(errMsgId, errString);
|
||||
|
||||
delegate.onResolutionRequired(AndroidUtils.getIdentifier("applock__fingerprint_error_unknown", "string"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
|
||||
super.onAuthenticationHelp(helpMsgId, helpString);
|
||||
|
||||
delegate.onAuthenticationHelp(helpMsgId, helpString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
|
||||
super.onAuthenticationSucceeded(result);
|
||||
|
||||
notifyEnrolled(context);
|
||||
|
||||
delegate.onAuthenticationSuccess(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
super.onAuthenticationFailed();
|
||||
}
|
||||
};
|
||||
|
||||
delegate.onAuthenticating(fingerprintCancellationSignal);
|
||||
|
||||
try {
|
||||
Cipher cipher = generateAuthCipher(context, false, 0);
|
||||
FingerprintManagerCompat.CryptoObject cryptoObject = new FingerprintManagerCompat.CryptoObject(cipher);
|
||||
|
||||
FingerprintManagerCompat manager = FingerprintManagerCompat.from(context);
|
||||
manager.authenticate(cryptoObject, 0, fingerprintCancellationSignal, callback, null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
delegate.onResolutionRequired(AppLock.ERROR_CODE_FINGERPRINTS_MISSING_HARDWARE);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isHardwarePresent(Context context) {
|
||||
return FingerprintManagerCompat.from(context).isHardwareDetected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnrolled(Context context) {
|
||||
return AppLock.getInstance(context).getPreferences().getBoolean(PREF_ENROLLMENT_ALLOWED, false);
|
||||
}
|
||||
|
||||
protected void notifyEnrolled(Context context) {
|
||||
AppLock.getInstance(context).getPreferences().edit().putBoolean(PREF_ENROLLMENT_ALLOWED, true).commit();
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
protected Cipher generateAuthCipher(Context context, boolean forceRegenerate, int attempts) throws Exception {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
|
||||
throw new RuntimeException("generateAuthCipher() not supported before Api 23");
|
||||
|
||||
return new CipherGenerator().generateAuthCipher(context, forceRegenerate, attempts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateEnrollments(Context context) {
|
||||
AppLock.getInstance(context).getPreferences().edit().putBoolean(PREF_ENROLLMENT_ALLOWED, false).commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelPendingAuthentications(Context context) {
|
||||
if (fingerprintCancellationSignal != null) {
|
||||
this.fingerprintCancellationSignal.cancel();
|
||||
this.fingerprintCancellationSignal = null;
|
||||
}
|
||||
}
|
||||
|
||||
public interface AuthenticationDelegate {
|
||||
void onResolutionRequired(int errorCode);
|
||||
|
||||
void onAuthenticationHelp(int code, CharSequence message);
|
||||
|
||||
void onAuthenticating(CancellationSignal cancellationSignal);
|
||||
|
||||
void onAuthenticationSuccess(FingerprintManagerCompat.AuthenticationResult result);
|
||||
|
||||
void onAuthenticationFailed(String message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.guardanis.applock.services;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
public abstract class LockService {
|
||||
|
||||
public abstract boolean isEnrolled(Context context);
|
||||
|
||||
public abstract boolean isEnrollmentEligible(Context context);
|
||||
|
||||
public abstract void cancelPendingAuthentications(Context context);
|
||||
|
||||
public abstract void invalidateEnrollments(Context context);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.guardanis.applock.services;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.guardanis.applock.AppLock;
|
||||
import com.guardanis.applock.utils.CryptoUtils;
|
||||
|
||||
public class PINLockService extends LockService {
|
||||
|
||||
private static final String PREF_SAVED_LOCKED_PASSWORD = "pin__saved_locked_password";
|
||||
|
||||
@Override
|
||||
public boolean isEnrollmentEligible(Context context) {
|
||||
// I couldn't find a good reason to allow the disabling of the PIN as an option.
|
||||
return true;
|
||||
}
|
||||
|
||||
public void authenticate(Context context, String pin, AuthenticationDelegate eventListener) {
|
||||
if (!isEnrolled(context)) {
|
||||
eventListener.onNoPIN();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!getEnrolledPIN(context).equals(CryptoUtils.encryptSha1(pin))) {
|
||||
eventListener.onPINDoesNotMatch();
|
||||
return;
|
||||
}
|
||||
|
||||
eventListener.onPINMatches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnrolled(Context context) {
|
||||
return AppLock.getInstance(context)
|
||||
.getPreferences()
|
||||
.getString(PREF_SAVED_LOCKED_PASSWORD, null) != null;
|
||||
}
|
||||
|
||||
private String getEnrolledPIN(Context context) {
|
||||
return AppLock.getInstance(context)
|
||||
.getPreferences()
|
||||
.getString(PREF_SAVED_LOCKED_PASSWORD, null);
|
||||
}
|
||||
|
||||
public void enroll(Context context, String pin) {
|
||||
AppLock.getInstance(context)
|
||||
.getPreferences()
|
||||
.edit()
|
||||
.putString(PREF_SAVED_LOCKED_PASSWORD, CryptoUtils.encryptSha1(pin))
|
||||
.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateEnrollments(Context context) {
|
||||
AppLock.getInstance(context)
|
||||
.getPreferences()
|
||||
.edit()
|
||||
.remove(PREF_SAVED_LOCKED_PASSWORD)
|
||||
.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelPendingAuthentications(Context context) {
|
||||
// There are none
|
||||
}
|
||||
|
||||
public interface AuthenticationDelegate {
|
||||
void onNoPIN();
|
||||
|
||||
void onPINDoesNotMatch();
|
||||
|
||||
void onPINMatches();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.guardanis.applock.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.security.keystore.KeyGenParameterSpec;
|
||||
import android.security.keystore.KeyPermanentlyInvalidatedException;
|
||||
import android.security.keystore.KeyProperties;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import java.security.KeyStore;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
public class CipherGenerator {
|
||||
|
||||
private static final String KEYSTORE_NAME = "AndroidKeyStore";
|
||||
|
||||
public Cipher generateAuthCipher(Context context, boolean forceRegenerate, int attempts) throws Exception {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
|
||||
throw new RuntimeException("generateAuthCipher() not supported before Api 23");
|
||||
|
||||
String alias = context.getString(AndroidUtils.getIdentifier("applock__fingerprint_alias", "string"));
|
||||
|
||||
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_NAME);
|
||||
keyStore.load(null);
|
||||
|
||||
if (forceRegenerate || !keyStore.containsAlias(alias)) {
|
||||
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_NAME);
|
||||
keyGenerator.init(new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
|
||||
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
|
||||
.setUserAuthenticationRequired(true)
|
||||
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
|
||||
.build());
|
||||
|
||||
keyGenerator.generateKey();
|
||||
}
|
||||
|
||||
String cipherFormat = String.format(
|
||||
"%s/%s/%s",
|
||||
KeyProperties.KEY_ALGORITHM_AES,
|
||||
KeyProperties.BLOCK_MODE_CBC,
|
||||
KeyProperties.ENCRYPTION_PADDING_PKCS7);
|
||||
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance(cipherFormat);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, keyStore.getKey(alias, null));
|
||||
|
||||
return cipher;
|
||||
} catch (KeyPermanentlyInvalidatedException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
if (1 < attempts)
|
||||
return generateAuthCipher(context, true, attempts + 1);
|
||||
} catch (UnrecoverableKeyException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
if (1 < attempts)
|
||||
return generateAuthCipher(context, true, attempts + 1);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.guardanis.applock.utils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class CryptoUtils {
|
||||
|
||||
public static String encryptSha1(String text) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
||||
md.update(text.getBytes(StandardCharsets.UTF_8), 0, text.length());
|
||||
|
||||
return convertToHex(md.digest());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String convertToHex(byte[] data) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
for (byte b : data) {
|
||||
int half = (b >>> 4) & 0x0F;
|
||||
int twoHalves = 0;
|
||||
|
||||
do {
|
||||
buf.append(half <= 9
|
||||
? (char) ('0' + half)
|
||||
: (char) ('a' + half - 10));
|
||||
|
||||
half = b & 0x0F;
|
||||
}
|
||||
while (twoHalves++ < 1);
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.guardanis.applock.utils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class LifeCycleUtils {
|
||||
|
||||
public static AppLockActivityLifeCycleCallbacks attach(Activity activity, AppLockActivityLifeCycleCallbacks.Delegate delegate) {
|
||||
AppLockActivityLifeCycleCallbacks callbacks = new AppLockActivityLifeCycleCallbacks(activity, delegate);
|
||||
|
||||
activity.getApplication()
|
||||
.registerActivityLifecycleCallbacks(callbacks);
|
||||
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
public static class AppLockActivityLifeCycleCallbacks implements Application.ActivityLifecycleCallbacks {
|
||||
|
||||
protected WeakReference<Activity> openedActivity;
|
||||
protected WeakReference<Delegate> delegate;
|
||||
|
||||
public AppLockActivityLifeCycleCallbacks(Activity activity, Delegate delegate) {
|
||||
this.openedActivity = new WeakReference<>(activity);
|
||||
this.delegate = new WeakReference<>(delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Activity activity, Bundle bundle) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStarted(Activity activity) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStopped(Activity activity) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResumed(Activity activity) {
|
||||
Activity opened = this.openedActivity.get();
|
||||
Delegate delegate = this.delegate.get();
|
||||
|
||||
if (opened == null || delegate == null || opened != activity)
|
||||
return;
|
||||
|
||||
delegate.onActivityResumed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused(Activity activity) {
|
||||
Activity opened = this.openedActivity.get();
|
||||
Delegate delegate = this.delegate.get();
|
||||
|
||||
if (opened == null || delegate == null || opened != activity)
|
||||
return;
|
||||
|
||||
delegate.onActivityPaused();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
Activity opened = this.openedActivity.get();
|
||||
|
||||
if (opened == null || opened != activity)
|
||||
return;
|
||||
|
||||
opened.getApplication()
|
||||
.unregisterActivityLifecycleCallbacks(this);
|
||||
}
|
||||
|
||||
public interface Delegate {
|
||||
void onActivityResumed();
|
||||
|
||||
void onActivityPaused();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package com.guardanis.applock.views;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.Intent;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
||||
import com.guardanis.applock.AppLock;
|
||||
import com.guardanis.applock.pin.PINInputController;
|
||||
import com.guardanis.applock.pin.PINInputView;
|
||||
import com.guardanis.applock.utils.LifeCycleUtils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public abstract class AppLockViewController implements LifeCycleUtils.AppLockActivityLifeCycleCallbacks.Delegate {
|
||||
|
||||
protected PINInputController pinInputController;
|
||||
|
||||
protected WeakReference<Activity> activity;
|
||||
protected WeakReference<View> parent;
|
||||
|
||||
protected WeakReference<PINInputView> pinInputView;
|
||||
|
||||
protected WeakReference<TextView> descriptionView;
|
||||
protected WeakReference<View> actionSettings;
|
||||
|
||||
protected boolean autoAuthorizationEnabled = true;
|
||||
|
||||
protected Application.ActivityLifecycleCallbacks activityLifecycleCallbacks;
|
||||
|
||||
public AppLockViewController(Activity activity, View parent) {
|
||||
this.activity = new WeakReference<>(activity);
|
||||
this.parent = new WeakReference<>(parent);
|
||||
this.descriptionView = new WeakReference<>(parent.findViewById(AndroidUtils.getIdentifier("pin__description", "id")));
|
||||
this.actionSettings = new WeakReference<>(parent.findViewById(AndroidUtils.getIdentifier("pin__action_settings", "id")));
|
||||
|
||||
this.pinInputView = new WeakReference<>(parent.findViewById(AndroidUtils.getIdentifier("pin__input_view", "id")));
|
||||
|
||||
int inputViewsCount = Integer.parseInt(AppLock.getPinCodeLimits(activity));
|
||||
|
||||
boolean passwordCharsEnabled = parent.getResources()
|
||||
.getBoolean(AndroidUtils.getIdentifier("applock__item_password_chars_enabled", "bool"));
|
||||
|
||||
this.pinInputController = new PINInputController(pinInputView.get())
|
||||
.setInputNumbersCount(inputViewsCount)
|
||||
.setPasswordCharactersEnabled(passwordCharsEnabled);
|
||||
|
||||
this.activityLifecycleCallbacks = LifeCycleUtils.attach(activity, this);
|
||||
}
|
||||
|
||||
public abstract void setupRootFlow();
|
||||
|
||||
public void setDescription(int descriptionResId) {
|
||||
final TextView descriptionView = this.descriptionView.get();
|
||||
|
||||
if (descriptionView == null)
|
||||
return;
|
||||
|
||||
descriptionView.setText(descriptionResId);
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
final TextView descriptionView = this.descriptionView.get();
|
||||
|
||||
if (descriptionView == null)
|
||||
return;
|
||||
|
||||
descriptionView.setText(description);
|
||||
}
|
||||
|
||||
protected <T extends View> void hide(WeakReference<T> weakView) {
|
||||
final T view = weakView.get();
|
||||
|
||||
if (view == null)
|
||||
return;
|
||||
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
protected <T extends View> void show(WeakReference<T> weakView) {
|
||||
final T view = weakView.get();
|
||||
|
||||
if (view == null)
|
||||
return;
|
||||
|
||||
view.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
public PINInputController getPINInputController() {
|
||||
return pinInputController;
|
||||
}
|
||||
|
||||
public View getParent() {
|
||||
return parent.get();
|
||||
}
|
||||
|
||||
public void setAutoAuthorizationEnabled(boolean autoAuthorizationEnabled) {
|
||||
this.autoAuthorizationEnabled = autoAuthorizationEnabled;
|
||||
}
|
||||
|
||||
public void updateActionSettings(final int errorCode) {
|
||||
View actionSettings = this.actionSettings.get();
|
||||
|
||||
if (actionSettings == null)
|
||||
return;
|
||||
|
||||
if (getSettingsIntent(errorCode) == null) {
|
||||
actionSettings.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
||||
actionSettings.setVisibility(View.VISIBLE);
|
||||
actionSettings.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View view) {
|
||||
handleActionSettingsClicked(errorCode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract void handleActionSettingsClicked(int errorCode);
|
||||
|
||||
protected void handleInitialErrorPrompt(int errorCode) {
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null)
|
||||
return;
|
||||
|
||||
if (errorCode == AppLock.ERROR_CODE_FINGERPRINTS_PERMISSION_REQUIRED) {
|
||||
ActivityCompat.requestPermissions(
|
||||
activity,
|
||||
new String[]{Manifest.permission.USE_FINGERPRINT},
|
||||
AppLock.REQUEST_CODE_FINGERPRINT_PERMISSION);
|
||||
}
|
||||
}
|
||||
|
||||
protected int getDescriptionResIdForError(int errorCode) {
|
||||
return switch (errorCode) {
|
||||
case AppLock.ERROR_CODE_FINGERPRINTS_PERMISSION_REQUIRED ->
|
||||
AndroidUtils.getIdentifier("applock__fingerprint_error_permission", "string");
|
||||
case AppLock.ERROR_CODE_FINGERPRINTS_EMPTY ->
|
||||
AndroidUtils.getIdentifier("applock__fingerprint_error_none", "string");
|
||||
case AppLock.ERROR_CODE_FINGERPRINTS_MISSING_HARDWARE ->
|
||||
AndroidUtils.getIdentifier("applock__fingerprint_error_hardware", "string");
|
||||
case AppLock.ERROR_CODE_FINGERPRINTS_NOT_LOCALLY_ENROLLED ->
|
||||
AndroidUtils.getIdentifier("applock__fingerprint_error_not_enrolled", "string");
|
||||
default -> AndroidUtils.getIdentifier("applock__fingerprint_error_unknown", "string");
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an Intent directed towards the correct system setting for the error, or null if there is none.
|
||||
*/
|
||||
public Intent getSettingsIntent(int errorCode) {
|
||||
return switch (errorCode) {
|
||||
case AppLock.ERROR_CODE_FINGERPRINTS_PERMISSION_REQUIRED, AppLock.ERROR_CODE_FINGERPRINTS_EMPTY, AppLock.ERROR_CODE_FINGERPRINTS_MISSING_HARDWARE ->
|
||||
new Intent(android.provider.Settings.ACTION_SECURITY_SETTINGS);
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
public void unregisterReceivers() {
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null)
|
||||
return;
|
||||
|
||||
activity.getApplication()
|
||||
.unregisterActivityLifecycleCallbacks(activityLifecycleCallbacks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResumed() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
package com.guardanis.applock.views;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.hardware.fingerprint.FingerprintManagerCompat;
|
||||
import androidx.core.os.CancellationSignal;
|
||||
|
||||
import com.guardanis.applock.AppLock;
|
||||
import com.guardanis.applock.pin.PINInputController;
|
||||
import com.guardanis.applock.services.FingerprintLockService;
|
||||
import com.guardanis.applock.services.PINLockService;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class LockCreationViewController extends AppLockViewController
|
||||
implements PINInputController.InputEventListener, FingerprintLockService.AuthenticationDelegate {
|
||||
|
||||
protected DisplayVariant displayVariant = DisplayVariant.NONE;
|
||||
protected WeakReference<Delegate> delegate;
|
||||
protected WeakReference<View> chooserParent;
|
||||
protected String pinFirst;
|
||||
|
||||
public LockCreationViewController(Activity activity, View parent) {
|
||||
super(activity, parent);
|
||||
|
||||
this.chooserParent = new WeakReference<>(parent.findViewById(AndroidUtils.getIdentifier("pin__create_chooser_items", "id")));
|
||||
}
|
||||
|
||||
public LockCreationViewController setDelegate(Delegate delegate) {
|
||||
this.delegate = new WeakReference<>(delegate);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupRootFlow() {
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null)
|
||||
return;
|
||||
|
||||
setupPINCreation();
|
||||
}
|
||||
|
||||
protected void setupPINCreation() {
|
||||
this.displayVariant = DisplayVariant.PIN_CREATION;
|
||||
|
||||
hide(chooserParent);
|
||||
hide(actionSettings);
|
||||
|
||||
show(pinInputView);
|
||||
|
||||
setDescription(AndroidUtils.getIdentifier("applock__description_create_pin", "string"));
|
||||
|
||||
pinInputController.ensureKeyboardVisible();
|
||||
pinInputController.setInputEventListener(this);
|
||||
}
|
||||
|
||||
protected void setupPINConfirmation() {
|
||||
this.displayVariant = DisplayVariant.PIN_CONFIRMATION;
|
||||
|
||||
hide(chooserParent);
|
||||
hide(actionSettings);
|
||||
|
||||
show(pinInputView);
|
||||
|
||||
setDescription(AndroidUtils.getIdentifier("applock__description_confirm", "string"));
|
||||
|
||||
pinInputController.ensureKeyboardVisible();
|
||||
pinInputController.setInputEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInputEntered(String input) {
|
||||
switch (displayVariant) {
|
||||
case PIN_CREATION -> {
|
||||
if (!pinInputController.matchesRequiredPINLength(input)) {
|
||||
setDescription(AndroidUtils.getIdentifier("applock__unlock_error_insufficient_selection", "string"));
|
||||
|
||||
return;
|
||||
}
|
||||
this.pinFirst = input;
|
||||
setupPINConfirmation();
|
||||
}
|
||||
case PIN_CONFIRMATION -> {
|
||||
if (!pinInputController.matchesRequiredPINLength(input)) {
|
||||
setDescription(AndroidUtils.getIdentifier("applock__unlock_error_insufficient_selection", "string"));
|
||||
|
||||
return;
|
||||
}
|
||||
if (!input.equals(pinFirst)) {
|
||||
this.pinFirst = null;
|
||||
|
||||
setupPINCreation();
|
||||
setDescription(AndroidUtils.getIdentifier("applock__description_create_pin_reattempt", "string"));
|
||||
|
||||
return;
|
||||
}
|
||||
createPINLock(input);
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void createPINLock(String input) {
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null)
|
||||
return;
|
||||
|
||||
AppLock.getInstance(activity)
|
||||
.getLockService(PINLockService.class)
|
||||
.enroll(activity, input);
|
||||
|
||||
var fingerprintLockService = AppLock.getInstance(activity).getLockService(FingerprintLockService.class);
|
||||
if (fingerprintLockService.isEnrollmentEligible(activity)) {
|
||||
setupFingerprintAuthentication();
|
||||
} else {
|
||||
handleLockCreated();
|
||||
}
|
||||
}
|
||||
|
||||
protected void setupFingerprintAuthentication() {
|
||||
this.displayVariant = DisplayVariant.FINGERPRINT_AUTHENTICATION;
|
||||
|
||||
hide(pinInputView);
|
||||
hide(chooserParent);
|
||||
hide(actionSettings);
|
||||
|
||||
setDescription(AndroidUtils.getIdentifier("applock__description_create_fingerprint", "string"));
|
||||
|
||||
if (autoAuthorizationEnabled)
|
||||
attemptFingerprintAuthentication();
|
||||
}
|
||||
|
||||
protected void attemptFingerprintAuthentication() {
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null)
|
||||
return;
|
||||
|
||||
AppLock.getInstance(activity)
|
||||
.getLockService(FingerprintLockService.class)
|
||||
.enroll(activity, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResolutionRequired(int errorCode) {
|
||||
setDescription(getDescriptionResIdForError(errorCode));
|
||||
updateActionSettings(errorCode);
|
||||
handleInitialErrorPrompt(errorCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationHelp(int code, CharSequence message) {
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null)
|
||||
return;
|
||||
|
||||
String unformattedHelpMessage = activity.getString(AndroidUtils.getIdentifier("applock__description_unlock_fingerprint_help", "string"));
|
||||
String formatted = String.format(unformattedHelpMessage, message);
|
||||
|
||||
setDescription(formatted);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticating(CancellationSignal cancellationSignal) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(FingerprintManagerCompat.AuthenticationResult result) {
|
||||
handleLockCreated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed(String message) {
|
||||
setDescription(message);
|
||||
}
|
||||
|
||||
protected void handleLockCreated() {
|
||||
this.displayVariant = DisplayVariant.NONE;
|
||||
|
||||
Delegate delegate = this.delegate.get();
|
||||
|
||||
if (delegate != null)
|
||||
delegate.onLockCreated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused() {
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null)
|
||||
return;
|
||||
|
||||
AppLock.getInstance(activity)
|
||||
.cancelPendingAuthentications();
|
||||
|
||||
if (displayVariant == DisplayVariant.FINGERPRINT_AUTHENTICATION)
|
||||
setDescription(AndroidUtils.getIdentifier("applock__description_create_fingerprint_paused", "string"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResumed() {
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null || displayVariant != DisplayVariant.FINGERPRINT_AUTHENTICATION)
|
||||
return;
|
||||
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
|
||||
setDescription(AndroidUtils.getIdentifier("applock__fingerprint_error_permission_multiple", "string"));
|
||||
updateActionSettings(AppLock.ERROR_CODE_FINGERPRINTS_PERMISSION_REQUIRED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setDescription(AndroidUtils.getIdentifier("applock__description_create_fingerprint", "string"));
|
||||
hide(actionSettings);
|
||||
|
||||
attemptFingerprintAuthentication();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleActionSettingsClicked(int errorCode) {
|
||||
Activity activity = this.activity.get();
|
||||
Intent intent = getSettingsIntent(errorCode);
|
||||
|
||||
if (activity == null || intent == null)
|
||||
return;
|
||||
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
|
||||
public enum DisplayVariant {
|
||||
NONE,
|
||||
PIN_CREATION,
|
||||
PIN_CONFIRMATION,
|
||||
FINGERPRINT_AUTHENTICATION
|
||||
}
|
||||
|
||||
public interface Delegate {
|
||||
void onLockCreated();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
package com.guardanis.applock.views;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.guardanis.applock.AppLock;
|
||||
import com.guardanis.applock.pin.PINInputController;
|
||||
import com.guardanis.applock.services.FingerprintLockService;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class UnlockViewController extends AppLockViewController implements AppLock.UnlockDelegate, PINInputController.InputEventListener {
|
||||
|
||||
protected DisplayVariant displayVariant = DisplayVariant.PIN_UNLOCK;
|
||||
protected WeakReference<Delegate> delegate;
|
||||
|
||||
public UnlockViewController(Activity activity, View parent) {
|
||||
super(activity, parent);
|
||||
}
|
||||
|
||||
public UnlockViewController setDelegate(Delegate delegate) {
|
||||
this.delegate = new WeakReference<Delegate>(delegate);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupRootFlow() {
|
||||
View parent = this.parent.get();
|
||||
|
||||
if (parent == null)
|
||||
return;
|
||||
|
||||
setupPINUnlock();
|
||||
}
|
||||
|
||||
protected void setupPINUnlock() {
|
||||
this.displayVariant = DisplayVariant.PIN_UNLOCK;
|
||||
|
||||
hide(actionSettings);
|
||||
show(pinInputView);
|
||||
|
||||
setDescription(AndroidUtils.getIdentifier("applock__description_unlock_pin", "string"));
|
||||
|
||||
requestOpenKeyboard();
|
||||
pinInputController.setInputEventListener(this);
|
||||
|
||||
FingerprintLockService fingerprintService = AppLock.getInstance(this.parent.get().getContext())
|
||||
.getLockService(FingerprintLockService.class);
|
||||
|
||||
if (fingerprintService.isEnrolled(parent.get().getContext()))
|
||||
attemptFingerprintAuthentication();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInputEntered(String input) {
|
||||
if (!pinInputController.matchesRequiredPINLength(input)) {
|
||||
setDescription(AndroidUtils.getIdentifier("applock__unlock_error_insufficient_selection", "string"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
attemptPINUnlock(input);
|
||||
}
|
||||
|
||||
protected void attemptPINUnlock(String input) {
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null)
|
||||
return;
|
||||
|
||||
AppLock.getInstance(activity)
|
||||
.attemptPINUnlock(input, this);
|
||||
}
|
||||
|
||||
protected void attemptFingerprintAuthentication() {
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null)
|
||||
return;
|
||||
|
||||
AppLock.getInstance(activity)
|
||||
.attemptFingerprintUnlock(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnlockSuccessful() {
|
||||
this.displayVariant = DisplayVariant.NONE;
|
||||
|
||||
Delegate delegate = this.delegate.get();
|
||||
|
||||
if (delegate != null)
|
||||
delegate.onUnlockSuccessful();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResolutionRequired(int errorCode) {
|
||||
setDescription(getDescriptionResIdForError(errorCode));
|
||||
updateActionSettings(errorCode);
|
||||
handleInitialErrorPrompt(errorCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationHelp(int code, String message) {
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null)
|
||||
return;
|
||||
|
||||
String unformattedHelpMessage = activity.getString(AndroidUtils.getIdentifier("applock__description_unlock_fingerprint_help", "string"));
|
||||
String formatted = String.format(unformattedHelpMessage, message);
|
||||
|
||||
setDescription(formatted);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailureLimitExceeded(String message) {
|
||||
setDescription(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestOpenKeyboard() {
|
||||
pinInputController.ensureKeyboardVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused() {
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null)
|
||||
return;
|
||||
|
||||
AppLock.getInstance(activity)
|
||||
.cancelPendingAuthentications();
|
||||
|
||||
if (displayVariant == DisplayVariant.FINGERPRINT_AUTHENTICATION)
|
||||
setDescription(AndroidUtils.getIdentifier("applock__description_create_fingerprint_paused", "string"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResumed() {
|
||||
Activity activity = this.activity.get();
|
||||
|
||||
if (activity == null || displayVariant != DisplayVariant.FINGERPRINT_AUTHENTICATION)
|
||||
return;
|
||||
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
|
||||
setDescription(AndroidUtils.getIdentifier("applock__fingerprint_error_permission_multiple", "string"));
|
||||
updateActionSettings(AppLock.ERROR_CODE_FINGERPRINTS_PERMISSION_REQUIRED);
|
||||
return;
|
||||
}
|
||||
|
||||
setDescription(AndroidUtils.getIdentifier("applock__description_unlock_fingerprint", "string"));
|
||||
hide(actionSettings);
|
||||
|
||||
attemptFingerprintAuthentication();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleActionSettingsClicked(int errorCode) {
|
||||
Activity activity = this.activity.get();
|
||||
Intent intent = getSettingsIntent(errorCode);
|
||||
|
||||
if (activity == null || intent == null)
|
||||
return;
|
||||
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
|
||||
public enum DisplayVariant {
|
||||
NONE,
|
||||
PIN_UNLOCK,
|
||||
FINGERPRINT_AUTHENTICATION
|
||||
}
|
||||
|
||||
public interface Delegate {
|
||||
void onUnlockSuccessful();
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,23 @@
|
||||
package com.vk.api.audio;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
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.lite.utils.Preferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ru.vtosters.lite.music.Genius;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class AudioGetLyrics extends ApiRequest<AudioGetLyrics.a> {
|
||||
private final MusicTrack musicTrack;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import b.h.v.InitialValueObservable;
|
||||
import b.h.v.TextViewTextChangeEvent;
|
||||
import b.h.v.TextViewTextChangeEventObservable;
|
||||
import com.vk.core.util.ContextExtKt;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
|
||||
public final class TextViewExt {
|
||||
public static void a(TextView textView, Drawable drawable) {
|
||||
|
||||
@@ -14,7 +14,7 @@ import com.vk.core.ui.themes.VKThemeHelper;
|
||||
import com.vk.dto.common.VerifyInfo;
|
||||
import com.vk.extensions.ViewExtKt;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
|
||||
|
||||
public final class VerifyInfoHelper {
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.vk.im.engine.models.dialogs.Dialog;
|
||||
import com.vk.im.engine.models.groups.Group;
|
||||
import com.vk.im.engine.utils.DialogPermissionHelper;
|
||||
import com.vk.im.ui.p.ImBridge7;
|
||||
import ru.vtosters.lite.dialogs.DialogMenuInjectors;
|
||||
import ru.vtosters.hooks.DialogMenuInjectors;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ import com.vk.im.ui.views.msg.MsgPartIconTwoRowView;
|
||||
import com.vtosters.lite.R;
|
||||
import kotlin.TypeCastException;
|
||||
import kotlin.jvm.internal.Intrinsics;
|
||||
import ru.vtosters.lite.hooks.CallsHook;
|
||||
import ru.vtosters.hooks.CallsHook;
|
||||
|
||||
public final class MsgPartCallHolder extends MsgPartHolderBase<AttachCall> {
|
||||
public static final a I = new a();
|
||||
|
||||
@@ -39,7 +39,7 @@ import com.vk.im.ui.views.avatars.AvatarView;
|
||||
import com.vk.im.ui.views.avatars.StoryBorderView;
|
||||
|
||||
import static com.vk.im.ui.d.vkim_administration_title;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getAccentColor;
|
||||
import static ru.vtosters.hooks.other.ThemesUtils.getAccentColor;
|
||||
|
||||
public class DialogItemView extends ViewGroup {
|
||||
private final int B;
|
||||
|
||||
@@ -4,7 +4,7 @@ import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.CompressFormat;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import ru.vtosters.lite.utils.Preferences;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
@@ -0,0 +1,502 @@
|
||||
package com.vk.medianative;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.os.Process;
|
||||
import android.os.*;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Scanner;
|
||||
|
||||
public final class MediaNative {
|
||||
private static final String a = NativeMediaEncoder.class.getSimpleName();
|
||||
private static final Object f17443d = new Object();
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
@Keep
|
||||
public static volatile Context context;
|
||||
private static boolean isMediaLoaded = false;
|
||||
private static boolean isMediaMasksLoaded = false;
|
||||
|
||||
public static int HSLToIntRGB(float f2, float f3, float f4) {
|
||||
int[] iArr = new int[3];
|
||||
waitForContext();
|
||||
nativeHSLToRGB(f2, f3, f4, iArr);
|
||||
return Color.argb(255, iArr[0], iArr[1], iArr[2]);
|
||||
}
|
||||
|
||||
public static void HSLToRGB(float f2, float f3, float f4, int[] iArr) {
|
||||
waitForContext();
|
||||
nativeHSLToRGB(f2, f3, f4, iArr);
|
||||
}
|
||||
|
||||
public static int HSVToIntRGB(float f2, float f3, float f4) {
|
||||
int[] iArr = new int[3];
|
||||
waitForContext();
|
||||
nativeHSVToRGB(f2, f3, f4, iArr);
|
||||
return Color.argb(255, iArr[0], iArr[1], iArr[2]);
|
||||
}
|
||||
|
||||
public static void HSVToRGB(float f2, float f3, float f4, int[] iArr) {
|
||||
waitForContext();
|
||||
nativeHSVToRGB(f2, f3, f4, iArr);
|
||||
}
|
||||
|
||||
public static int LabToIntRGB(float f2, float f3, float f4) {
|
||||
int[] iArr = new int[3];
|
||||
waitForContext();
|
||||
nativeLabToRGB(f2, f3, f4, iArr);
|
||||
return Color.argb(255, iArr[0], iArr[1], iArr[2]);
|
||||
}
|
||||
|
||||
public static void LabToRGB(float f2, float f3, float f4, int[] iArr) {
|
||||
waitForContext();
|
||||
nativeLabToRGB(f2, f3, f4, iArr);
|
||||
}
|
||||
|
||||
public static void RGBToHSL(int i, int i2, int i3, float[] fArr) {
|
||||
waitForContext();
|
||||
nativeRGBToHSL(i, i2, i3, fArr);
|
||||
}
|
||||
|
||||
public static void RGBToHSV(int i, int i2, int i3, float[] fArr) {
|
||||
waitForContext();
|
||||
nativeRGBToHSV(i, i2, i3, fArr);
|
||||
}
|
||||
|
||||
public static void RGBToLab(int i, int i2, int i3, float[] fArr) {
|
||||
waitForContext();
|
||||
nativeRGBToLab(i, i2, i3, fArr);
|
||||
}
|
||||
|
||||
public static long animationPlayerCreate(String str, int i, int i2, boolean z) {
|
||||
waitForContext();
|
||||
return nativeAnimationPlayerCreate(str, i, i2, z);
|
||||
}
|
||||
|
||||
public static int animationPlayerDecode(long j, Bitmap bitmap) {
|
||||
waitForContext();
|
||||
return nativeAnimationPlayerDecode(j, bitmap);
|
||||
}
|
||||
|
||||
public static int animationPlayerGetSize(long j) {
|
||||
waitForContext();
|
||||
return nativeAnimationPlayerGetSize(j);
|
||||
}
|
||||
|
||||
public static void animationPlayerRelease(long j) {
|
||||
waitForContext();
|
||||
nativeAnimationPlayerRelease(j);
|
||||
}
|
||||
|
||||
public static boolean animationPlayerSeek(long j, int i) {
|
||||
waitForContext();
|
||||
return nativeAnimationPlayerSeek(j, i);
|
||||
}
|
||||
|
||||
public static void applyCurveAndSaturationBitmap(Bitmap bitmap, int[] iArr, float f2) {
|
||||
waitForContext();
|
||||
nativeCurveSaturation(bitmap, iArr, f2, Runtime.getRuntime().availableProcessors());
|
||||
}
|
||||
|
||||
public static long audioGetTotalPcmDuration() {
|
||||
waitForContext();
|
||||
return nativeAudioGetTotalPcmDuration();
|
||||
}
|
||||
|
||||
public static byte[] audioGetWaveform(short[] sArr, int i) {
|
||||
waitForContext();
|
||||
return nativeAudioGetWaveform(sArr, i);
|
||||
}
|
||||
|
||||
public static int audioIsOpusFile(String str) {
|
||||
waitForContext();
|
||||
return nativeAudioIsOpusFile(str);
|
||||
}
|
||||
|
||||
public static void audioReadOpusFile(ByteBuffer byteBuffer, int i, int[] iArr) {
|
||||
waitForContext();
|
||||
nativeAudioReadOpusFile(byteBuffer, i, iArr);
|
||||
}
|
||||
|
||||
public static int audioSeekOpusFile(float f2) {
|
||||
waitForContext();
|
||||
return nativeAudioSeekOpusFile(f2);
|
||||
}
|
||||
|
||||
public static int audioStartRecord(String str) { // need to hack
|
||||
waitForContext();
|
||||
return nativeAudioStartRecord(str);
|
||||
}
|
||||
|
||||
public static void audioStopRecord() { // need to hack
|
||||
waitForContext();
|
||||
nativeAudioStopRecord();
|
||||
}
|
||||
|
||||
public static int audioWriteFrame(ByteBuffer byteBuffer, int i) { // need to hack
|
||||
waitForContext();
|
||||
return nativeAudioWriteFrame(byteBuffer, i);
|
||||
}
|
||||
|
||||
private static void waitForContext() {
|
||||
synchronized (f17443d) {
|
||||
if (context == null) {
|
||||
try {
|
||||
f17443d.wait();
|
||||
} catch (InterruptedException e2) {
|
||||
Log.e(a, "Interrupted while waiting for context", e2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void blurBitmap(Bitmap bitmap, int i) {
|
||||
waitForContext();
|
||||
nativeBlur(bitmap, i);
|
||||
}
|
||||
|
||||
private static String c() {
|
||||
return getProcMaps(String.valueOf(Process.myPid()));
|
||||
}
|
||||
|
||||
public static void cameraProcessorCreate() {
|
||||
waitForContext();
|
||||
nativeProcessorCreate();
|
||||
}
|
||||
|
||||
public static boolean cameraProcessorDo(byte[] bArr, long[] jArr) {
|
||||
waitForContext();
|
||||
return nativeProcessorDo(bArr, jArr);
|
||||
}
|
||||
|
||||
public static int cameraProcessorGetVersion() {
|
||||
waitForContext();
|
||||
return nativeProcessorGetVersion();
|
||||
}
|
||||
|
||||
public static boolean cameraProcessorInit(String str, int i, int i2) {
|
||||
waitForContext();
|
||||
return nativeProcessorInit(str, i, i2);
|
||||
}
|
||||
|
||||
public static boolean cameraProcessorLoad(String str, boolean z) {
|
||||
waitForContext();
|
||||
return nativeProcessorLoad(str, z);
|
||||
}
|
||||
|
||||
public static void cameraProcessorMouseTap(int i, float f2, float f3) {
|
||||
waitForContext();
|
||||
nativeProcessorMouseTap(i, f2, f3);
|
||||
}
|
||||
|
||||
public static void cameraProcessorRelease() {
|
||||
waitForContext();
|
||||
nativeProcessorRelease();
|
||||
}
|
||||
|
||||
public static void colorCorrectionBitmap(Bitmap bitmap, Bitmap bitmap2, float[] fArr) {
|
||||
waitForContext();
|
||||
nativeColorCorrection(bitmap, bitmap2, fArr, fArr.length, Runtime.getRuntime().availableProcessors());
|
||||
}
|
||||
|
||||
public static byte[] compressBitmapJpeg(Bitmap bitmap, int i) {
|
||||
waitForContext();
|
||||
return nativeJpegTurboCompress(bitmap, i);
|
||||
}
|
||||
|
||||
public static String createAllInOneShader() {
|
||||
waitForContext();
|
||||
return nativeAllInOneShader();
|
||||
}
|
||||
|
||||
public static void createCurve(int[] iArr, int[] iArr2, int[] iArr3, int[] iArr4, int[] iArr5, float f2, float f3, float f4, float f5, float f6) {
|
||||
waitForContext();
|
||||
nativeCreateCurve(iArr, iArr2, iArr3, iArr4, iArr5, f2, f3, f4, f5, f6);
|
||||
}
|
||||
|
||||
public static String createOneInAllShader() {
|
||||
waitForContext();
|
||||
return nativeOneInAllShader();
|
||||
}
|
||||
|
||||
private static String d() {
|
||||
return getProcMaps("self");
|
||||
}
|
||||
|
||||
public static String dump() {
|
||||
return "LD_LIBRARY_PATH:\n" + SoLoader.makeLdLibraryPath() + "\nSELF_MAPS:\n" + d() + "\nPID_MAPS:\n" + c() + "\n";
|
||||
}
|
||||
|
||||
private static void e() {
|
||||
isMediaMasksLoaded = NativeLibLoader.loadLibrary("vkmediamasks");
|
||||
}
|
||||
|
||||
public static void enhanceBitmap(Bitmap bitmap, float f2) {
|
||||
waitForContext();
|
||||
nativeEnhance(bitmap, f2, Runtime.getRuntime().availableProcessors());
|
||||
}
|
||||
|
||||
private static void loadVKMediaLibs() {
|
||||
if (isMediaLoaded) {
|
||||
return;
|
||||
}
|
||||
NativeLibLoader.loadLibrary("ffmpeg");
|
||||
isMediaLoaded = NativeLibLoader.loadLibrary("vkmedia");
|
||||
isMediaLoaded = NativeLibLoader.loadLibrary("vkmediaencoder");
|
||||
}
|
||||
|
||||
public static void flipHorizontallyBitmap(Bitmap bitmap) {
|
||||
waitForContext();
|
||||
nativeFlipHorizontally(bitmap);
|
||||
}
|
||||
|
||||
public static void flipVerticallyBitmap(Bitmap bitmap) {
|
||||
waitForContext();
|
||||
nativeFlipVertically(bitmap);
|
||||
}
|
||||
|
||||
public static void generateHistogram(Bitmap bitmap, int[] iArr, int[] iArr2, int[] iArr3, int[] iArr4) {
|
||||
waitForContext();
|
||||
nativeHistogram(bitmap, iArr, iArr2, iArr3, iArr4);
|
||||
}
|
||||
|
||||
public static void init(Context context2) {
|
||||
synchronized (f17443d) {
|
||||
context = context2;
|
||||
SoLoader.init(context2, false);
|
||||
NativeLibLoader.loadLibrary("gnustl_shared");
|
||||
NativeLibLoader.loadLibrary("vkchronicle");
|
||||
loadVKMediaLibs();
|
||||
f17443d.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public static void intRGBToHSL(int i, float[] fArr) {
|
||||
waitForContext();
|
||||
nativeRGBToHSL(Color.red(i), Color.green(i), Color.blue(i), fArr);
|
||||
}
|
||||
|
||||
public static void intRGBToHSV(int i, float[] fArr) {
|
||||
waitForContext();
|
||||
nativeRGBToHSV(Color.red(i), Color.green(i), Color.blue(i), fArr);
|
||||
}
|
||||
|
||||
public static void intRGBToLab(int i, float[] fArr) {
|
||||
waitForContext();
|
||||
nativeRGBToLab(Color.red(i), Color.green(i), Color.blue(i), fArr);
|
||||
}
|
||||
|
||||
public static boolean isAsus() {
|
||||
return "asus".equalsIgnoreCase(Build.MANUFACTURER);
|
||||
}
|
||||
|
||||
public static boolean isMediaSupported() {
|
||||
if (!isMediaMasksLoaded) {
|
||||
e();
|
||||
}
|
||||
return isMediaMasksLoaded;
|
||||
}
|
||||
|
||||
public static boolean isX86() {
|
||||
try {
|
||||
String str = Build.SUPPORTED_ABIS[0];
|
||||
if (str != null) {
|
||||
return str.startsWith("x86");
|
||||
}
|
||||
return false;
|
||||
} catch (Throwable unused) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void lookupBitmap(Bitmap bitmap, Bitmap bitmap2) {
|
||||
waitForContext();
|
||||
nativeLookup(bitmap, bitmap2, Runtime.getRuntime().availableProcessors());
|
||||
}
|
||||
|
||||
public static long mediaEncoderCreate(MediaEncoderSettings mediaEncoderSettings) {
|
||||
waitForContext();
|
||||
return nativeCreateEncoder(mediaEncoderSettings);
|
||||
}
|
||||
|
||||
public static int mediaEncoderDoEncode(long j) {
|
||||
waitForContext();
|
||||
return nativeDoEncode(j);
|
||||
}
|
||||
|
||||
public static void mediaEncoderDoRelease(long j) {
|
||||
waitForContext();
|
||||
nativeReleaseEncoder(j);
|
||||
}
|
||||
|
||||
private static native String nativeAllInOneShader();
|
||||
|
||||
private static native long nativeAnimationPlayerCreate(String str, int i, int i2, boolean z);
|
||||
|
||||
private static native int nativeAnimationPlayerDecode(long j, Bitmap bitmap);
|
||||
|
||||
private static native int nativeAnimationPlayerGetSize(long j);
|
||||
|
||||
private static native void nativeAnimationPlayerRelease(long j);
|
||||
|
||||
private static native boolean nativeAnimationPlayerSeek(long j, int i);
|
||||
|
||||
private static native long nativeAudioGetTotalPcmDuration();
|
||||
|
||||
private static native byte[] nativeAudioGetWaveform(short[] sArr, int i);
|
||||
|
||||
private static native int nativeAudioIsOpusFile(String str);
|
||||
|
||||
private static native int nativeAudioOpenOpusFile(String str);
|
||||
|
||||
private static native void nativeAudioReadOpusFile(ByteBuffer byteBuffer, int i, int[] iArr);
|
||||
|
||||
private static native int nativeAudioSeekOpusFile(float f2);
|
||||
|
||||
private static native int nativeAudioStartRecord(String str);
|
||||
|
||||
private static native void nativeAudioStopRecord();
|
||||
|
||||
private static native int nativeAudioWriteFrame(ByteBuffer byteBuffer, int i);
|
||||
|
||||
private static native void nativeBlur(Bitmap bitmap, int i);
|
||||
|
||||
private static native void nativeColorCorrection(Bitmap bitmap, Bitmap bitmap2, float[] fArr, int i, int i2);
|
||||
|
||||
private static native String nativeCreateColorCorrectionShader(float[] fArr, int i, int i2);
|
||||
|
||||
private static native void nativeCreateCurve(int[] iArr, int[] iArr2, int[] iArr3, int[] iArr4, int[] iArr5, float f2, float f3, float f4, float f5, float f6);
|
||||
|
||||
private static native long nativeCreateEncoder(MediaEncoderSettings mediaEncoderSettings);
|
||||
|
||||
private static native void nativeCurveSaturation(Bitmap bitmap, int[] iArr, double d2, int i);
|
||||
|
||||
private static native int nativeDoEncode(long j);
|
||||
|
||||
private static native void nativeEnhance(Bitmap bitmap, double d2, int i);
|
||||
|
||||
private static native void nativeFlipHorizontally(Bitmap bitmap);
|
||||
|
||||
private static native void nativeFlipVertically(Bitmap bitmap);
|
||||
|
||||
private static native void nativeHSLToRGB(float f2, float f3, float f4, int[] iArr);
|
||||
|
||||
private static native void nativeHSVToRGB(float f2, float f3, float f4, int[] iArr);
|
||||
|
||||
private static native void nativeHistogram(Bitmap bitmap, int[] iArr, int[] iArr2, int[] iArr3, int[] iArr4);
|
||||
|
||||
private static native byte[] nativeJpegTurboCompress(Bitmap bitmap, int i);
|
||||
|
||||
private static native void nativeLabToRGB(float f2, float f3, float f4, int[] iArr);
|
||||
|
||||
private static native void nativeLookup(Bitmap bitmap, Bitmap bitmap2, int i);
|
||||
|
||||
private static native String nativeOneInAllShader();
|
||||
|
||||
private static native void nativePinBitmap(Bitmap bitmap);
|
||||
|
||||
private static native void nativeProcessorCreate();
|
||||
|
||||
private static native boolean nativeProcessorDo(byte[] bArr, long[] jArr);
|
||||
|
||||
private static native int nativeProcessorGetVersion();
|
||||
|
||||
private static native boolean nativeProcessorInit(String str, int i, int i2);
|
||||
|
||||
private static native boolean nativeProcessorLoad(String str, boolean z);
|
||||
|
||||
private static native void nativeProcessorMouseTap(int i, float f2, float f3);
|
||||
|
||||
private static native void nativeProcessorRelease();
|
||||
|
||||
private static native void nativeRGBToHSL(int i, int i2, int i3, float[] fArr);
|
||||
|
||||
private static native void nativeRGBToHSV(int i, int i2, int i3, float[] fArr);
|
||||
|
||||
private static native void nativeRGBToLab(int i, int i2, int i3, float[] fArr);
|
||||
|
||||
private static native void nativeReleaseEncoder(long j);
|
||||
|
||||
private static native void nativeResize(Bitmap bitmap, Bitmap bitmap2, int i);
|
||||
|
||||
public static int openOpusFile(String str) {
|
||||
waitForContext();
|
||||
return nativeAudioOpenOpusFile(str);
|
||||
}
|
||||
|
||||
public static void pinBitmap(Bitmap bitmap) {
|
||||
waitForContext();
|
||||
nativePinBitmap(bitmap);
|
||||
}
|
||||
|
||||
public static void resizeBitmap(Bitmap bitmap, Bitmap bitmap2) {
|
||||
waitForContext();
|
||||
nativeResize(bitmap, bitmap2, Runtime.getRuntime().availableProcessors());
|
||||
}
|
||||
|
||||
private static String getProcMaps(String str) {
|
||||
try (InputStream inputStream = Runtime.getRuntime().exec("cat /proc/" + str + "/maps").getInputStream()) {
|
||||
return new Scanner(inputStream).useDelimiter("\\A").next();
|
||||
} catch (Exception e) {
|
||||
return "empty";
|
||||
}
|
||||
}
|
||||
|
||||
public static class EncoderHandler extends Handler {
|
||||
private Callback a;
|
||||
|
||||
public EncoderHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Keep
|
||||
public static Object postEventFromNative(Object obj, int i, int i2, int i3) {
|
||||
EncoderHandler encoderHandler;
|
||||
if (obj != null && (encoderHandler = (EncoderHandler) ((WeakReference<?>) obj).get()) != null) {
|
||||
if (i == 2) {
|
||||
return encoderHandler.a.getLayerBitmap(i2, i3);
|
||||
}
|
||||
encoderHandler.sendMessage(encoderHandler.obtainMessage(i, i2, i3, null));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override // android.os.Handler
|
||||
public void handleMessage(Message message) {
|
||||
Callback callback = this.a;
|
||||
if (callback == null) {
|
||||
return;
|
||||
}
|
||||
int i = message.what;
|
||||
if (i == 0) {
|
||||
callback.onBytes(message.arg1);
|
||||
} else if (i != 1) {
|
||||
String str = MediaNative.a;
|
||||
Log.e(str, "Unknown message type " + message.what);
|
||||
} else {
|
||||
callback.onProgress(message.arg1);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCallback(Callback callback) {
|
||||
this.a = callback;
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
@Nullable
|
||||
Bitmap getLayerBitmap(int i, int i2);
|
||||
|
||||
void onBytes(int i);
|
||||
|
||||
void onProgress(int i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.music.Genius;
|
||||
import ru.vtosters.lite.utils.Preferences;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@@ -18,12 +18,12 @@ import com.vk.imageloader.view.VKMultiImageView;
|
||||
import com.vk.navigation.NavigatorKeys;
|
||||
import com.vtosters.lite.R;
|
||||
import com.vtosters.lite.a0;
|
||||
import ru.vtosters.lite.utils.Preferences;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static b.h.z.f.roboto_medium;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getAccentColor;
|
||||
import static ru.vtosters.hooks.other.ThemesUtils.getAccentColor;
|
||||
|
||||
@UiThread
|
||||
public class TargetImageView extends VKMultiImageView {
|
||||
|
||||
@@ -2140,6 +2140,8 @@ public final class R {
|
||||
public static final int im_ic_msgdl = 0x7f040774; // 2130970484
|
||||
public static final int im_ic_msgreload = 0x7f040775; // 2130970485
|
||||
public static final int im_ic_stats = 0x7f040776; // 2130970486
|
||||
public static final int pinBackgroundColor = 0x7f040777; // 2130970487
|
||||
public static final int pinTextColor = 0x7f040778; // 2130970488
|
||||
}
|
||||
|
||||
public static final class bool {
|
||||
@@ -2160,6 +2162,9 @@ public final class R {
|
||||
public static final int spb_default_reversed = 0x7f05000e; // 2131034126
|
||||
public static final int vk_is_tablet = 0x7f05000f; // 2131034127
|
||||
public static final int com_samsung_android_icon_container_has_icon_container = 0x7f050010; // 2131034128
|
||||
public static final int applock__fingerprint_service_enabled = 0x7f050011; // 2131034129
|
||||
public static final int applock__item_password_chars_enabled = 0x7f050012; // 2131034130
|
||||
public static final int applock__unlock_activity_return_allowed = 0x7f050013; // 2131034131
|
||||
}
|
||||
|
||||
public static final class color {
|
||||
@@ -2968,6 +2973,13 @@ public final class R {
|
||||
public static final int yellow_light = 0x7f060323; // 2131100451
|
||||
public static final int yellow_sunflower = 0x7f060324; // 2131100452
|
||||
public static final int iclauncher = 0x7f060325; // 2131100453
|
||||
public static final int applock__action_settings = 0x7f060327; // 2131100455
|
||||
public static final int applock__activity_background = 0x7f060328; // 2131100456
|
||||
public static final int applock__create_choose_option_bg = 0x7f060329; // 2131100457
|
||||
public static final int applock__create_choose_option_bg_pressed = 0x7f06032a; // 2131100458
|
||||
public static final int applock__description_text = 0x7f06032b; // 2131100459
|
||||
public static final int applock__item_background = 0x7f06032c; // 2131100460
|
||||
public static final int applock__item_text = 0x7f06032d; // 2131100461
|
||||
public static final int abc_color_highlight_material = 0x7f060004; // 2131099652
|
||||
public static final int alpha05 = 0x7f060326; // 2131100454
|
||||
}
|
||||
@@ -3821,6 +3833,21 @@ public final class R {
|
||||
public static final int wrap_content = 0x7f07035b; // 2131166043
|
||||
public static final int year_label_height = 0x7f07035c; // 2131166044
|
||||
public static final int year_label_text_size = 0x7f07035d; // 2131166045
|
||||
public static final int applock__action_settings = 0x7f07035e; // 2131166046
|
||||
public static final int applock__action_settings_margin_top = 0x7f07035f; // 2131166047
|
||||
public static final int applock__action_settings_padding = 0x7f070360; // 2131166048
|
||||
public static final int applock__activity_padding = 0x7f070361; // 2131166049
|
||||
public static final int applock__chooser_image_size = 0x7f070362; // 2131166050
|
||||
public static final int applock__chooser_parent_padding_vertical = 0x7f070363; // 2131166051
|
||||
public static final int applock__chooser_text_padding_top = 0x7f070364; // 2131166052
|
||||
public static final int applock__content_padding_horizontal = 0x7f070365; // 2131166053
|
||||
public static final int applock__content_padding_vertical = 0x7f070366; // 2131166054
|
||||
public static final int applock__description_padding_bottom = 0x7f070367; // 2131166055
|
||||
public static final int applock__description_text = 0x7f070368; // 2131166056
|
||||
public static final int applock__fingerprint_scan_image_margin_top = 0x7f070369; // 2131166057
|
||||
public static final int applock__fingerprint_scan_image_size = 0x7f07036a; // 2131166058
|
||||
public static final int applock__item_margin_top = 0x7f07036b; // 2131166059
|
||||
public static final int applock__item_size = 0x7f07036c; // 2131166060
|
||||
public static final int vkim_article_blocked_bottom_margin = 0x7f070329; // 2131165993
|
||||
public static final int vkim_article_blocked_ic_margin = 0x7f07032a; // 2131165994
|
||||
public static final int vkim_article_blocked_ic_size = 0x7f07032b; // 2131165995
|
||||
@@ -4976,30 +5003,32 @@ public final class R {
|
||||
public static final int ic_deepl_logo_icon = 0x7f080bcb; // 2131233739
|
||||
public static final int ic_google_translate_logo = 0x7f080bcc; // 2131233740
|
||||
public static final int ic_yandex_translate_icon = 0x7f080bd1; // 2131233745
|
||||
public static final int microsoft = 0x7f080bd2; // 2131233746
|
||||
public static final int $splash__0 = 0x7f080bd2; // 2131233746
|
||||
public static final int roundmsg = 0x7f080bd3; // 2131233747
|
||||
public static final int tgs_entry_background = 0x7f080bd4; // 2131233748
|
||||
public static final int yandex = 0x7f080bd7; // 2131233751
|
||||
public static final int $splash__0 = 0x7f080bd8; // 2131233752
|
||||
public static final int $splash__1 = 0x7f080bd9; // 2131233753
|
||||
public static final int $splash__10 = 0x7f080bda; // 2131233754
|
||||
public static final int $splash__11 = 0x7f080bdb; // 2131233755
|
||||
public static final int $splash__12 = 0x7f080bdc; // 2131233756
|
||||
public static final int $splash__13 = 0x7f080bdd; // 2131233757
|
||||
public static final int $splash__14 = 0x7f080bde; // 2131233758
|
||||
public static final int $splash__15 = 0x7f080bdf; // 2131233759
|
||||
public static final int $splash__2 = 0x7f080be0; // 2131233760
|
||||
public static final int $splash__3 = 0x7f080be1; // 2131233761
|
||||
public static final int $splash__4 = 0x7f080be2; // 2131233762
|
||||
public static final int $splash__5 = 0x7f080be3; // 2131233763
|
||||
public static final int $splash__6 = 0x7f080be4; // 2131233764
|
||||
public static final int $splash__7 = 0x7f080be5; // 2131233765
|
||||
public static final int $splash__8 = 0x7f080be6; // 2131233766
|
||||
public static final int $splash__9 = 0x7f080be7; // 2131233767
|
||||
public static final int $splash__1 = 0x7f080bd8; // 2131233752
|
||||
public static final int $splash__10 = 0x7f080bd9; // 2131233753
|
||||
public static final int $splash__11 = 0x7f080bda; // 2131233754
|
||||
public static final int $splash__12 = 0x7f080bdb; // 2131233755
|
||||
public static final int $splash__13 = 0x7f080bdc; // 2131233756
|
||||
public static final int $splash__14 = 0x7f080bdd; // 2131233757
|
||||
public static final int $splash__15 = 0x7f080bde; // 2131233758
|
||||
public static final int $splash__2 = 0x7f080bdf; // 2131233759
|
||||
public static final int $splash__3 = 0x7f080be0; // 2131233760
|
||||
public static final int $splash__4 = 0x7f080be1; // 2131233761
|
||||
public static final int $splash__5 = 0x7f080be2; // 2131233762
|
||||
public static final int $splash__6 = 0x7f080be3; // 2131233763
|
||||
public static final int $splash__7 = 0x7f080be4; // 2131233764
|
||||
public static final int $splash__8 = 0x7f080be5; // 2131233765
|
||||
public static final int $splash__9 = 0x7f080be6; // 2131233766
|
||||
public static final int checker_background = 0x7f080be8; // 2131233768
|
||||
public static final int custom_thumb_selector = 0x7f080be9; // 2131233769
|
||||
public static final int custom_track_selector = 0x7f080bea; // 2131233770
|
||||
public static final int splash = 0x7f080beb; // 2131233771
|
||||
public static final int splash = 0x7f080bec; // 2131233772
|
||||
public static final int applock__chooser_option_bg = 0x7f080bee; // 2131233774
|
||||
public static final int applock__fingerprint = 0x7f080bef; // 2131233775
|
||||
public static final int applock__pin = 0x7f080bf0; // 2131233776
|
||||
public static final int abc_control_background_material = 0x7f080032; // 2131230770
|
||||
public static final int ic_action_close = 0x7f080322; // 2131231522
|
||||
public static final int ic_camera_outline_28_new = 0x7f0803a0; // 2131231648
|
||||
@@ -6797,6 +6826,9 @@ public final class R {
|
||||
public static final int ic_telegram_24 = 0x7f080bcf; // 2131233743
|
||||
public static final int ic_telegram_outline_28 = 0x7f080bd0; // 2131233744
|
||||
public static final int vtlogo = 0x7f080bd6; // 2131233750
|
||||
public static final int bing = 0x7f080be7; // 2131233767
|
||||
public static final int sauceNAO = 0x7f080beb; // 2131233771
|
||||
public static final int tracemoe = 0x7f080bed; // 2131233773
|
||||
public static final int bg_music_play_button_white = 0x7f08015e; // 2131231070
|
||||
public static final int bg_poll_bg_thumb = 0x7f080181; // 2131231105
|
||||
public static final int bg_stickers_suggestions_left = 0x7f0801ad; // 2131231149
|
||||
@@ -11060,6 +11092,12 @@ public final class R {
|
||||
public static final int color_preview_border = 0x7f0a1024; // 2131365924
|
||||
public static final int account_backup_view = 0x7f0a1025; // 2131365925
|
||||
public static final int copy_image = 0x7f0a1026; // 2131365926
|
||||
public static final int applock__activity_lock_creation = 0x7f0a1027; // 2131365927
|
||||
public static final int applock__activity_unlock = 0x7f0a1028; // 2131365928
|
||||
public static final int pin__action_settings = 0x7f0a1029; // 2131365929
|
||||
public static final int pin__container = 0x7f0a102a; // 2131365930
|
||||
public static final int pin__description = 0x7f0a102b; // 2131365931
|
||||
public static final int pin__input_view = 0x7f0a102c; // 2131365932
|
||||
}
|
||||
|
||||
public static final class integer {
|
||||
@@ -11106,6 +11144,10 @@ public final class R {
|
||||
public static final int status_bar_notification_info_maxnum = 0x7f0b002b; // 2131427371
|
||||
public static final int vkim_activity_animation_duration = 0x7f0b002c; // 2131427372
|
||||
public static final int vkim_playing_drawable_rect_count = 0x7f0b002d; // 2131427373
|
||||
public static final int applock__activity_lock_reenable_minutes = 0x7f0b002e; // 2131427374
|
||||
public static final int applock__failure_retry_delay = 0x7f0b002f; // 2131427375
|
||||
public static final int applock__input_pin_item_count = 0x7f0b0030; // 2131427376
|
||||
public static final int applock__max_retry_count = 0x7f0b0031; // 2131427377
|
||||
public static final int emoji_size_in_sprite = 0x7f0b0012; // 2131427346
|
||||
public static final int s1dip = 0x7f0b0027; // 2131427367
|
||||
public static final int s2dip = 0x7f0b0028; // 2131427368
|
||||
@@ -12881,6 +12923,11 @@ public final class R {
|
||||
public static final int wppreview = 0x7f0d06df; // 2131560159
|
||||
public static final int write_bar_i = 0x7f0d06e0; // 2131560160
|
||||
public static final int color_picker_item = 0x7f0d06e1; // 2131560161
|
||||
public static final int applock__activity_lock_creation = 0x7f0d06e2; // 2131560162
|
||||
public static final int applock__activity_unlock = 0x7f0d06e3; // 2131560163
|
||||
public static final int applock__fake_edit_text = 0x7f0d06e4; // 2131560164
|
||||
public static final int applock__lock_creation = 0x7f0d06e5; // 2131560165
|
||||
public static final int applock__unlock = 0x7f0d06e6; // 2131560166
|
||||
}
|
||||
|
||||
public static final class menu {
|
||||
@@ -19592,67 +19639,107 @@ public final class R {
|
||||
public static final int calls_not_available = 0x7f12184a; // 2131892298
|
||||
public static final int cannot_write = 0x7f12184b; // 2131892299
|
||||
public static final int change_accent_color = 0x7f12184c; // 2131892300
|
||||
public static final int copydebuginfo_summ = 0x7f12184d; // 2131892301
|
||||
public static final int copydebuginfo_title = 0x7f12184e; // 2131892302
|
||||
public static final int copyownlink_summ = 0x7f12184f; // 2131892303
|
||||
public static final int copyownlink_title = 0x7f121850; // 2131892304
|
||||
public static final int crash_service_name = 0x7f121851; // 2131892305
|
||||
public static final int currentLanguage = 0x7f121852; // 2131892306
|
||||
public static final int current_theme = 0x7f121853; // 2131892307
|
||||
public static final int custom_links_warning = 0x7f121854; // 2131892308
|
||||
public static final int data = 0x7f121855; // 2131892309
|
||||
public static final int data_updated = 0x7f121856; // 2131892310
|
||||
public static final int datasettings_title = 0x7f121857; // 2131892311
|
||||
public static final int device_info = 0x7f121858; // 2131892312
|
||||
public static final int device_info_copied = 0x7f121859; // 2131892313
|
||||
public static final int dialogstats = 0x7f12185a; // 2131892314
|
||||
public static final int disable_analytics = 0x7f12185b; // 2131892315
|
||||
public static final int disable_analytics_summ = 0x7f12185c; // 2131892316
|
||||
public static final int downloading_update = 0x7f12185d; // 2131892317
|
||||
public static final int error_applying_accent = 0x7f12185e; // 2131892318
|
||||
public static final int error_no_text = 0x7f12185f; // 2131892319
|
||||
public static final int error_saving_file = 0x7f121860; // 2131892320
|
||||
public static final int failed_to_get_text = 0x7f121861; // 2131892321
|
||||
public static final int invalid_pack_link = 0x7f121862; // 2131892322
|
||||
public static final int invalidate_theme_cache_title = 0x7f121863; // 2131892323
|
||||
public static final int logColors_title = 0x7f121864; // 2131892324
|
||||
public static final int maxquality_summ = 0x7f121865; // 2131892325
|
||||
public static final int maxquality_title = 0x7f121866; // 2131892326
|
||||
public static final int monettheme_summ = 0x7f121867; // 2131892327
|
||||
public static final int monettheme_title = 0x7f121868; // 2131892328
|
||||
public static final int newsfeed_notif_summ = 0x7f121869; // 2131892329
|
||||
public static final int newsfeed_notif_title = 0x7f12186a; // 2131892330
|
||||
public static final int open_bot = 0x7f12186b; // 2131892331
|
||||
public static final int promotedstickers_title = 0x7f12186c; // 2131892332
|
||||
public static final int remove_encryption_key = 0x7f12186d; // 2131892333
|
||||
public static final int remove_from_ads_stories_whitelist = 0x7f12186e; // 2131892334
|
||||
public static final int reset_accounts = 0x7f12186f; // 2131892335
|
||||
public static final int reset_all_settings = 0x7f121870; // 2131892336
|
||||
public static final int restore_accounts = 0x7f121871; // 2131892337
|
||||
public static final int restore_settings = 0x7f121872; // 2131892338
|
||||
public static final int save_accounts = 0x7f121873; // 2131892339
|
||||
public static final int save_online_data = 0x7f121874; // 2131892340
|
||||
public static final int select_color = 0x7f121875; // 2131892341
|
||||
public static final int select_palette = 0x7f121876; // 2131892342
|
||||
public static final int sources = 0x7f121877; // 2131892343
|
||||
public static final int storiesGroupsAdBlock = 0x7f121878; // 2131892344
|
||||
public static final int storiesGroupsAdBlocksummary = 0x7f121879; // 2131892345
|
||||
public static final int systemtheme = 0x7f12187a; // 2131892346
|
||||
public static final int systemtheme_enabled = 0x7f12187b; // 2131892347
|
||||
public static final int systemtheme_summ = 0x7f12187c; // 2131892348
|
||||
public static final int updateverifdata_summ = 0x7f12187d; // 2131892349
|
||||
public static final int updateverifdata_title = 0x7f12187e; // 2131892350
|
||||
public static final int useCustomPrefsStyle_summ = 0x7f12187f; // 2131892351
|
||||
public static final int useCustomPrefsStyle_title = 0x7f121880; // 2131892352
|
||||
public static final int useGenius_summ = 0x7f121881; // 2131892353
|
||||
public static final int useGenius_title = 0x7f121882; // 2131892354
|
||||
public static final int useNewColorEngine_summ = 0x7f121883; // 2131892355
|
||||
public static final int useNewColorEngine_title = 0x7f121884; // 2131892356
|
||||
public static final int useOldAppVer_summ = 0x7f121885; // 2131892357
|
||||
public static final int useOldAppVer_title = 0x7f121886; // 2131892358
|
||||
public static final int vkx_integration_enabled_info = 0x7f121887; // 2131892359
|
||||
public static final int whitelisted_ad_groups_stories_title = 0x7f121888; // 2131892360
|
||||
public static final int writebar_ios_title = 0x7f121889; // 2131892361
|
||||
public static final int compression_types = 0x7f12184d; // 2131892301
|
||||
public static final int compression_types_selection = 0x7f12184e; // 2131892302
|
||||
public static final int copydebuginfo_summ = 0x7f12184f; // 2131892303
|
||||
public static final int copydebuginfo_title = 0x7f121850; // 2131892304
|
||||
public static final int copyownlink_summ = 0x7f121851; // 2131892305
|
||||
public static final int copyownlink_title = 0x7f121852; // 2131892306
|
||||
public static final int crash_service_name = 0x7f121853; // 2131892307
|
||||
public static final int currentLanguage = 0x7f121854; // 2131892308
|
||||
public static final int current_theme = 0x7f121855; // 2131892309
|
||||
public static final int custom_links_warning = 0x7f121856; // 2131892310
|
||||
public static final int data = 0x7f121857; // 2131892311
|
||||
public static final int data_updated = 0x7f121858; // 2131892312
|
||||
public static final int datasettings_title = 0x7f121859; // 2131892313
|
||||
public static final int device_info = 0x7f12185a; // 2131892314
|
||||
public static final int device_info_copied = 0x7f12185b; // 2131892315
|
||||
public static final int dialogstats = 0x7f12185c; // 2131892316
|
||||
public static final int disable_analytics = 0x7f12185d; // 2131892317
|
||||
public static final int disable_analytics_summ = 0x7f12185e; // 2131892318
|
||||
public static final int downloading_update = 0x7f12185f; // 2131892319
|
||||
public static final int error_applying_accent = 0x7f121860; // 2131892320
|
||||
public static final int error_no_text = 0x7f121861; // 2131892321
|
||||
public static final int error_saving_file = 0x7f121862; // 2131892322
|
||||
public static final int failed_to_get_text = 0x7f121863; // 2131892323
|
||||
public static final int invalid_pack_link = 0x7f121864; // 2131892324
|
||||
public static final int invalidate_theme_cache_title = 0x7f121865; // 2131892325
|
||||
public static final int logColors_title = 0x7f121866; // 2131892326
|
||||
public static final int maxquality_summ = 0x7f121867; // 2131892327
|
||||
public static final int maxquality_title = 0x7f121868; // 2131892328
|
||||
public static final int microgsett = 0x7f121869; // 2131892329
|
||||
public static final int monettheme_summ = 0x7f12186a; // 2131892330
|
||||
public static final int monettheme_title = 0x7f12186b; // 2131892331
|
||||
public static final int newsfeed_notif_summ = 0x7f12186c; // 2131892332
|
||||
public static final int newsfeed_notif_title = 0x7f12186d; // 2131892333
|
||||
public static final int open_bot = 0x7f12186e; // 2131892334
|
||||
public static final int promotedstickers_title = 0x7f12186f; // 2131892335
|
||||
public static final int remove_encryption_key = 0x7f121870; // 2131892336
|
||||
public static final int remove_from_ads_stories_whitelist = 0x7f121871; // 2131892337
|
||||
public static final int reset_accounts = 0x7f121872; // 2131892338
|
||||
public static final int reset_all_settings = 0x7f121873; // 2131892339
|
||||
public static final int restore_accounts = 0x7f121874; // 2131892340
|
||||
public static final int restore_settings = 0x7f121875; // 2131892341
|
||||
public static final int save_accounts = 0x7f121876; // 2131892342
|
||||
public static final int save_online_data = 0x7f121877; // 2131892343
|
||||
public static final int select_color = 0x7f121878; // 2131892344
|
||||
public static final int select_palette = 0x7f121879; // 2131892345
|
||||
public static final int sources = 0x7f12187a; // 2131892346
|
||||
public static final int storiesGroupsAdBlock = 0x7f12187b; // 2131892347
|
||||
public static final int storiesGroupsAdBlocksummary = 0x7f12187c; // 2131892348
|
||||
public static final int systemtheme = 0x7f12187d; // 2131892349
|
||||
public static final int systemtheme_enabled = 0x7f12187e; // 2131892350
|
||||
public static final int systemtheme_summ = 0x7f12187f; // 2131892351
|
||||
public static final int updateverifdata_summ = 0x7f121880; // 2131892352
|
||||
public static final int updateverifdata_title = 0x7f121881; // 2131892353
|
||||
public static final int useCustomPrefsStyle_summ = 0x7f121882; // 2131892354
|
||||
public static final int useCustomPrefsStyle_title = 0x7f121883; // 2131892355
|
||||
public static final int useGenius_summ = 0x7f121884; // 2131892356
|
||||
public static final int useGenius_title = 0x7f121885; // 2131892357
|
||||
public static final int useNewColorEngine_summ = 0x7f121886; // 2131892358
|
||||
public static final int useNewColorEngine_title = 0x7f121887; // 2131892359
|
||||
public static final int useOldAppVer_summ = 0x7f121888; // 2131892360
|
||||
public static final int useOldAppVer_title = 0x7f121889; // 2131892361
|
||||
public static final int vkx_integration_enabled_info = 0x7f12188a; // 2131892362
|
||||
public static final int whitelisted_ad_groups_stories_title = 0x7f12188b; // 2131892363
|
||||
public static final int writebar_ios_title = 0x7f12188c; // 2131892364
|
||||
public static final int applock__action_settings = 0x7f12188d; // 2131892365
|
||||
public static final int applock__create_chooser_option_fingerprint = 0x7f12188e; // 2131892366
|
||||
public static final int applock__create_chooser_option_pin = 0x7f12188f; // 2131892367
|
||||
public static final int applock__description_chooser = 0x7f121890; // 2131892368
|
||||
public static final int applock__description_confirm = 0x7f121891; // 2131892369
|
||||
public static final int applock__description_create_fingerprint = 0x7f121892; // 2131892370
|
||||
public static final int applock__description_create_fingerprint_paused = 0x7f121893; // 2131892371
|
||||
public static final int applock__description_create_pin = 0x7f121894; // 2131892372
|
||||
public static final int applock__description_create_pin_reattempt = 0x7f121895; // 2131892373
|
||||
public static final int applock__description_unlock_fingerprint = 0x7f121896; // 2131892374
|
||||
public static final int applock__description_unlock_fingerprint_help = 0x7f121897; // 2131892375
|
||||
public static final int applock__description_unlock_pin = 0x7f121898; // 2131892376
|
||||
public static final int applock__empty_item_min_size_percent = 0x7f121899; // 2131892377
|
||||
public static final int applock__fingerprint_alias = 0x7f12189a; // 2131892378
|
||||
public static final int applock__fingerprint_error_hardware = 0x7f12189b; // 2131892379
|
||||
public static final int applock__fingerprint_error_none = 0x7f12189c; // 2131892380
|
||||
public static final int applock__fingerprint_error_not_enrolled = 0x7f12189d; // 2131892381
|
||||
public static final int applock__fingerprint_error_permission = 0x7f12189e; // 2131892382
|
||||
public static final int applock__fingerprint_error_permission_multiple = 0x7f12189f; // 2131892383
|
||||
public static final int applock__fingerprint_error_unknown = 0x7f1218a0; // 2131892384
|
||||
public static final int applock__fingerprint_error_unrecognized = 0x7f1218a1; // 2131892385
|
||||
public static final int applock__password_char = 0x7f1218a2; // 2131892386
|
||||
public static final int applock__toast_unlock_required = 0x7f1218a3; // 2131892387
|
||||
public static final int applock__unlock_error_insufficient_selection = 0x7f1218a4; // 2131892388
|
||||
public static final int applock__unlock_error_match_failed = 0x7f1218a5; // 2131892389
|
||||
public static final int applock__unlock_error_no_matching_pin_found = 0x7f1218a6; // 2131892390
|
||||
public static final int applock__unlock_error_retry_limit_exceeded = 0x7f1218a7; // 2131892391
|
||||
public static final int cache_size = 0x7f1218a8; // 2131892392
|
||||
public static final int cache_size_summ = 0x7f1218a9; // 2131892393
|
||||
public static final int clear_all_cache = 0x7f1218aa; // 2131892394
|
||||
public static final int invalidate_theme_cache_each_update_title = 0x7f1218ab; // 2131892395
|
||||
public static final int invertFilters = 0x7f1218ac; // 2131892396
|
||||
public static final int invertFilters_summ = 0x7f1218ad; // 2131892397
|
||||
public static final int invertcached_summ = 0x7f1218ae; // 2131892398
|
||||
public static final int invertcached_title = 0x7f1218af; // 2131892399
|
||||
public static final int pin_not_set = 0x7f1218b0; // 2131892400
|
||||
public static final int pin_reset = 0x7f1218b1; // 2131892401
|
||||
}
|
||||
|
||||
public static final class style {
|
||||
@@ -20788,6 +20875,11 @@ public final class R {
|
||||
public static final int VkAmoledTheme = 0x7f130472; // 2131952754
|
||||
public static final int VkMilkAmoledStyle = 0x7f130473; // 2131952755
|
||||
public static final int VkMilkAmoledTheme = 0x7f130474; // 2131952756
|
||||
public static final int applock__action_settings = 0x7f130487; // 2131952775
|
||||
public static final int applock__content_parent = 0x7f130488; // 2131952776
|
||||
public static final int applock__description = 0x7f130489; // 2131952777
|
||||
public static final int applock__input_fingerprint_view = 0x7f13048a; // 2131952778
|
||||
public static final int applock__input_pin_view = 0x7f13048b; // 2131952779
|
||||
public static final int Base_V23_Theme_AppCompat = 0x7f13009d; // 2131951773
|
||||
public static final int Base_V23_Theme_AppCompat_Light = 0x7f13009e; // 2131951774
|
||||
public static final int Platform_V25_AppCompat = 0x7f13017f; // 2131951999
|
||||
|
||||
+2
-2
@@ -26,8 +26,8 @@ import com.vk.core.ui.themes.VKThemeHelper;
|
||||
import com.vtosters.lite.R;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
import static ru.vtosters.lite.utils.Preferences.vkme;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getCSTDock;
|
||||
import static ru.vtosters.hooks.other.Preferences.vkme;
|
||||
import static ru.vtosters.hooks.other.ThemesUtils.getCSTDock;
|
||||
|
||||
public class BottomNavigationItemView extends FrameLayout implements MenuView.ItemView {
|
||||
private final TextView mSmallLabel;
|
||||
|
||||
+7
-4
@@ -1,14 +1,17 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.view.View;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.VersionReader;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.devmenu;
|
||||
import static ru.vtosters.hooks.other.Preferences.getBuildName;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getApplicationName;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
|
||||
import static ru.vtosters.lite.utils.Preferences.devmenu;
|
||||
import static ru.vtosters.lite.utils.Preferences.getBuildName;
|
||||
|
||||
public class About {
|
||||
public class AboutHook {
|
||||
public static void inject(View view) {
|
||||
view.setOnLongClickListener(v -> {
|
||||
if (devmenu()) {
|
||||
@@ -0,0 +1,21 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.utils.NewsFeedFiltersUtils;
|
||||
|
||||
public class AdBlockHook {
|
||||
public static JSONObject discoverInject(JSONObject json) throws JSONException {
|
||||
return NewsFeedFiltersUtils.discoverInject(json);
|
||||
}
|
||||
|
||||
public static JSONArray feedInject(JSONArray items) {
|
||||
return NewsFeedFiltersUtils.feedInject(items);
|
||||
|
||||
}
|
||||
|
||||
public static JSONObject storiesads(JSONObject json, boolean isDeleteFix) throws JSONException {
|
||||
return NewsFeedFiltersUtils.storiesads(json, isDeleteFix);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import b.h.g.g.BuildInfo;
|
||||
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
|
||||
public class AppVerHook {
|
||||
public static int appBuild() {
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
|
||||
public class BusinessNotifHook {
|
||||
public static boolean hook(boolean i) {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -0,0 +1,27 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.music.injectors.CatalogJsonInjector;
|
||||
|
||||
public class CatalogsHook {
|
||||
public static JSONObject injectCatalogGetAudio(JSONObject json) {
|
||||
try {
|
||||
return CatalogJsonInjector.music(json);
|
||||
} catch (JSONException e) {
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
public static JSONObject injectCatalogGetAudioArtist(JSONObject json) {
|
||||
try {
|
||||
return CatalogJsonInjector.fixArtists(json);
|
||||
} catch (JSONException e) {
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
public static JSONObject injectCatalogGetSection(JSONObject json) {
|
||||
return CatalogJsonInjector.injectIntoCatalogs(json);
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
@@ -17,11 +17,11 @@ import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static ru.vtosters.lite.dialogs.DialogHeaderInjector.forceInvalidateDialogActions;
|
||||
import static ru.vtosters.hooks.DialogHeaderInjector.forceInvalidateDialogActions;
|
||||
import static ru.vtosters.hooks.other.ThemesUtils.getSTextAttr;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
|
||||
import static ru.vtosters.lite.utils.LifecycleUtils.getCurrentActivity;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getSTextAttr;
|
||||
|
||||
public class CryptImHook {
|
||||
public static boolean isPrivateProcessor(int peerID) {
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import com.vtosters.lite.R;
|
||||
@@ -8,8 +8,8 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.getString;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getStringDate;
|
||||
import static ru.vtosters.lite.utils.Preferences.getString;
|
||||
|
||||
public class DateHook {
|
||||
public static boolean fulltime() {
|
||||
+7
-9
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentValues;
|
||||
@@ -12,18 +12,16 @@ import com.vk.im.engine.models.messages.NestedMsg;
|
||||
import com.vk.libsqliteext.CustomSqliteExtensionsKt;
|
||||
import io.requery.android.database.sqlite.SQLiteDatabase;
|
||||
import io.requery.android.database.sqlite.SQLiteOpenHelper;
|
||||
import ru.vtosters.lite.encryption.EncryptProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
import static ru.vtosters.hooks.other.Preferences.getString;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import static ru.vtosters.lite.utils.Preferences.getString;
|
||||
|
||||
public class DeletedMessagesHandler {
|
||||
public class DeletedMessagesHook {
|
||||
private static List<Integer> sDeletedMessagesList = new ArrayList<>();
|
||||
|
||||
private static SQLiteDatabase sVKSQLiteDatabase;
|
||||
private static int sBodyIndex = -1;
|
||||
private static DeletedMessagesDBHelper sVTDatabase;
|
||||
@@ -60,13 +58,13 @@ public class DeletedMessagesHandler {
|
||||
for (NestedMsg nestedMsg : nestedMsgs) {
|
||||
if (!nestedMsg.w0().isEmpty()) checkForNestedMsg(nestedMsg.w0());
|
||||
|
||||
nestedMsg.d(EncryptProvider.decryptMessage(nestedMsg.f(), nestedMsg.getFrom().getId()));
|
||||
nestedMsg.d(EncryptionMessagesHook.decryptMessage(nestedMsg.f(), nestedMsg.getFrom().getId()));
|
||||
}
|
||||
}
|
||||
|
||||
private static void editTextOfMsg(MsgFromUser msgFromUser) {
|
||||
if (!msgFromUser.f().startsWith(getPrefixUndelete())) {
|
||||
msgFromUser.d(getPrefixUndelete() + EncryptProvider.decryptMessage(msgFromUser));
|
||||
msgFromUser.d(getPrefixUndelete() + EncryptionMessagesHook.decryptMessage(msgFromUser));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +85,7 @@ public class DeletedMessagesHandler {
|
||||
@SuppressLint("Range")
|
||||
int localId = cursor.getInt(cursor.getColumnIndex("local_id"));
|
||||
|
||||
var className = DeletedMessagesHandler.class.getSimpleName();
|
||||
var className = DeletedMessagesHook.class.getSimpleName();
|
||||
var imEnvironment = msgDeleteLpTask.b;
|
||||
var cint = msgDeleteLpTask.c;
|
||||
imEnvironment.a(className, new OnMsgUpdateEvent(className, cint, localId));
|
||||
+2
-2
@@ -1,13 +1,13 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.MD5;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
|
||||
public class DeviceInfoHook {
|
||||
public static String getDeviceInfo(String input) {
|
||||
+6
-6
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.dialogs;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Environment;
|
||||
@@ -8,11 +8,11 @@ import com.vk.im.engine.models.EntityIntMap;
|
||||
import com.vk.im.engine.models.dialogs.Dialog;
|
||||
import com.vk.im.ui.components.common.DialogAction;
|
||||
import com.vk.im.ui.views.dialog_actions.DialogActionsListView;
|
||||
import ru.vtosters.lite.dialogs.Requests;
|
||||
import ru.vtosters.lite.downloaders.messages.HtmlDialogDownloaderFormatProvider;
|
||||
import ru.vtosters.lite.downloaders.messages.MessagesDownloader;
|
||||
import ru.vtosters.lite.encryption.EncryptProvider;
|
||||
import ru.vtosters.lite.encryption.base.IMProcessor;
|
||||
import ru.vtosters.lite.hooks.CryptImHook;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.io.File;
|
||||
@@ -35,12 +35,12 @@ public class DialogHeaderInjector {
|
||||
forceInvalidateDialogActions(dialog);
|
||||
}
|
||||
case DNR_ON, DNR_OFF -> {
|
||||
DNRModule.hookDNR(peerId);
|
||||
MessagesActivityHook.hookDNR(peerId);
|
||||
forceInvalidateDialogActions(dialog);
|
||||
return true;
|
||||
}
|
||||
case DNT_ON, DNT_OFF -> {
|
||||
DNRModule.hookDNT(peerId);
|
||||
MessagesActivityHook.hookDNT(peerId);
|
||||
forceInvalidateDialogActions(dialog);
|
||||
return true;
|
||||
}
|
||||
@@ -84,13 +84,13 @@ public class DialogHeaderInjector {
|
||||
|
||||
actions.add(DialogAction.DOWNLOAD);
|
||||
|
||||
if (DNRModule.isDnrEnabledFor(peerId)) {
|
||||
if (MessagesActivityHook.isDnrEnabledFor(peerId)) {
|
||||
actions.add(DialogAction.DNR_OFF);
|
||||
} else {
|
||||
actions.add(DialogAction.DNR_ON);
|
||||
}
|
||||
|
||||
if (DNRModule.isDntEnabledFor(peerId)) {
|
||||
if (MessagesActivityHook.isDntEnabledFor(peerId)) {
|
||||
actions.add(DialogAction.DNT_OFF);
|
||||
} else {
|
||||
actions.add(DialogAction.DNT_ON);
|
||||
+6
-6
@@ -1,14 +1,14 @@
|
||||
package ru.vtosters.lite.dialogs;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.os.Environment;
|
||||
import com.vk.im.engine.models.dialogs.Dialog;
|
||||
import com.vk.im.ui.components.common.DialogAction;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.lite.dialogs.Requests;
|
||||
import ru.vtosters.lite.downloaders.messages.HtmlDialogDownloaderFormatProvider;
|
||||
import ru.vtosters.lite.downloaders.messages.MessagesDownloader;
|
||||
import ru.vtosters.lite.encryption.EncryptProvider;
|
||||
import ru.vtosters.lite.encryption.base.IMProcessor;
|
||||
import ru.vtosters.lite.hooks.CryptImHook;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -30,9 +30,9 @@ public class DialogMenuInjectors {
|
||||
list.add(DialogAction.pinmsg);
|
||||
list.add(DialogAction.unpinmsg);
|
||||
|
||||
list.add(DNRModule.isDnrEnabledFor(peerId) ? DialogAction.DNR_OFF : DialogAction.DNR_ON);
|
||||
list.add(MessagesActivityHook.isDnrEnabledFor(peerId) ? DialogAction.DNR_OFF : DialogAction.DNR_ON);
|
||||
|
||||
list.add(DNRModule.isDntEnabledFor(peerId) ? DialogAction.DNT_OFF : DialogAction.DNT_ON);
|
||||
list.add(MessagesActivityHook.isDntEnabledFor(peerId) ? DialogAction.DNT_OFF : DialogAction.DNT_ON);
|
||||
|
||||
list.add(DialogAction.ENCRYPT);
|
||||
|
||||
@@ -83,11 +83,11 @@ public class DialogMenuInjectors {
|
||||
return true;
|
||||
}
|
||||
case DNR_ON, DNR_OFF -> {
|
||||
DNRModule.hookDNR(peerId);
|
||||
MessagesActivityHook.hookDNR(peerId);
|
||||
return true;
|
||||
}
|
||||
case DNT_ON, DNT_OFF -> {
|
||||
DNRModule.hookDNT(peerId);
|
||||
MessagesActivityHook.hookDNT(peerId);
|
||||
return true;
|
||||
}
|
||||
case pinmsg -> {
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
package ru.vtosters.lite.dialogs;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.content.Context;
|
||||
import com.vk.im.engine.models.messages.Msg;
|
||||
import com.vk.im.engine.models.messages.MsgFromUser;
|
||||
import com.vk.im.ui.components.common.MsgAction;
|
||||
import com.vk.im.ui.components.viewcontrollers.popup.DelegateMsg;
|
||||
import ru.vtosters.lite.encryption.EncryptProvider;
|
||||
import ru.vtosters.lite.dialogs.Requests;
|
||||
import ru.vtosters.lite.ui.dialogs.Translate;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
@@ -37,7 +37,7 @@ public class DialogMessageInjector {
|
||||
var isTextExist = !text.isEmpty() && !text.equals(" ");
|
||||
|
||||
if (isTextExist) {
|
||||
Translate.showTranslatedText(context, EncryptProvider.decryptMessage(text, peerId));
|
||||
Translate.showTranslatedText(context, EncryptionMessagesHook.decryptMessage(text, peerId));
|
||||
} else {
|
||||
AndroidUtils.sendToast(context.getString(com.vtosters.lite.R.string.translator_no_text));
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.feature.discover;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import com.vk.dto.discover.DiscoverItem;
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.view.Menu;
|
||||
@@ -24,10 +24,10 @@ import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
import static com.vtosters.lite.R.id.*;
|
||||
import static ru.vtosters.hooks.other.Preferences.*;
|
||||
import static ru.vtosters.hooks.other.ThemesUtils.getCSTDock;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getResources;
|
||||
import static ru.vtosters.lite.utils.Preferences.*;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getCSTDock;
|
||||
|
||||
public class DockBarInjector {
|
||||
private static final DockBarEditorManager sManager = DockBarEditorManager.getInstance();
|
||||
@@ -0,0 +1,40 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.content.Context;
|
||||
import com.vk.core.dialogs.bottomsheet.MenuBottomSheetAction;
|
||||
import com.vk.dto.common.VideoFile;
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import com.vk.dto.stories.model.StoryEntry;
|
||||
import ru.vtosters.lite.downloaders.AudioDownloader;
|
||||
import ru.vtosters.lite.downloaders.StoryDownloader;
|
||||
import ru.vtosters.lite.downloaders.VideoDownloader;
|
||||
import ru.vtosters.lite.utils.ExternalLinkParser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class DownloadersHook {
|
||||
public static boolean onClickVideo(int id, VideoFile video, Context ctx) {
|
||||
if (id == VideoDownloader.DOWNLOAD_ID) {
|
||||
VideoDownloader.downloadVideo(video, ctx);
|
||||
return true;
|
||||
} else if (id == VideoDownloader.OPEN_EXTERNAL_LINK_ID) {
|
||||
ExternalLinkParser.parseVideoFile(video, ctx, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void injectActionVideo(ArrayList<MenuBottomSheetAction> list, VideoFile video) {
|
||||
if (!video.U && !video.I1()) {
|
||||
VideoDownloader.addAction(list, VideoDownloader.DOWNLOAD_ID, com.vtosters.lite.R.drawable.ic_download_outline_24, com.vtosters.lite.R.string.download, 9);
|
||||
VideoDownloader.addAction(list, VideoDownloader.OPEN_EXTERNAL_LINK_ID, com.vtosters.lite.R.drawable.ic_link_outline_28, com.vtosters.lite.R.string.interfacevideoext_short, 9);
|
||||
}
|
||||
}
|
||||
|
||||
public static Runnable injectActionStory(StoryEntry story) {
|
||||
return () -> StoryDownloader.downloadStory(story);
|
||||
}
|
||||
|
||||
public static void injectCacheAudio(MusicTrack mt) {
|
||||
AudioDownloader.cacheTrack(mt);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.util.Log;
|
||||
import com.vk.im.engine.models.messages.Msg;
|
||||
import com.vk.im.engine.models.messages.MsgFromUser;
|
||||
import com.vk.im.ui.components.msg_list.MsgListComponent;
|
||||
import ru.vtosters.lite.encryption.EncryptProvider;
|
||||
import ru.vtosters.lite.encryption.base.IMProcessor;
|
||||
|
||||
import static ru.vtosters.hooks.MessagesHook.injectOwnText;
|
||||
import static ru.vtosters.hooks.MessagesHook.injectOwnTextAll;
|
||||
|
||||
public class EncryptionMessagesHook {
|
||||
// For message editing
|
||||
public static String decryptMessage(MsgFromUser msg, boolean showEmoji) {
|
||||
var decryptedMessage = decryptMessage(EncryptProvider.getBody(msg), EncryptProvider.getPeerId(msg));
|
||||
if (!showEmoji && !decryptedMessage.equals(injectOwnTextAll(EncryptProvider.getBody(msg))))
|
||||
decryptedMessage = decryptedMessage.replaceAll("^\uD83D\uDD12 ", "");
|
||||
return decryptedMessage;
|
||||
}
|
||||
|
||||
public static String decryptMessage(String msg, MsgListComponent list) {
|
||||
var peerid = list.G().getId();
|
||||
var decryptedMessage = decryptMessage(msg, peerid);
|
||||
if (!decryptedMessage.equals(injectOwnTextAll(msg)))
|
||||
decryptedMessage = decryptedMessage.replaceAll("^\uD83D\uDD12 ", "");
|
||||
return decryptedMessage;
|
||||
}
|
||||
|
||||
public static CharSequence decryptMessage(CharSequence msg, int peerid) {
|
||||
return decryptMessage(msg.toString(), peerid);
|
||||
}
|
||||
|
||||
public static CharSequence decryptMessage(Msg msg, CharSequence orig) {
|
||||
if (msg instanceof MsgFromUser) {
|
||||
var decrypted = decryptMessage(((MsgFromUser) msg).f(), msg.v1());
|
||||
|
||||
if (decrypted.contains("\uD83D\uDD12")) {
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return orig;
|
||||
}
|
||||
|
||||
public static String decryptMessages(String msgBody, int peer, boolean showEmoji) {
|
||||
return (String) decryptMessage(msgBody, peer, showEmoji);
|
||||
}
|
||||
|
||||
public static CharSequence decryptMessage(CharSequence msgBody, MsgFromUser msgFromUser, boolean showEmoji) {
|
||||
try {
|
||||
return decryptMessage((String) msgBody, msgFromUser.v1(), showEmoji);
|
||||
} catch (Exception e) {
|
||||
return decryptMessage((String) msgBody, 0, showEmoji);
|
||||
}
|
||||
}
|
||||
|
||||
// For MentionsFormatter that requires CharSequence
|
||||
public static CharSequence decryptMessage(String msgBody, int peer, boolean showEmoji) {
|
||||
var decryptedMessage = decryptMessage(msgBody, peer);
|
||||
if (!showEmoji && !decryptedMessage.equals(injectOwnTextAll(msgBody)))
|
||||
decryptedMessage = decryptedMessage.replaceAll("^\uD83D\uDD12 ", "");
|
||||
return decryptedMessage;
|
||||
}
|
||||
|
||||
// This will run through EVERY single processor available.
|
||||
public static String decryptMessage(MsgFromUser msg) {
|
||||
return decryptMessage(EncryptProvider.getBody(msg), EncryptProvider.getPeerId(msg));
|
||||
}
|
||||
|
||||
public static String decryptMessage(String msgBody, int peer) {
|
||||
try {
|
||||
for (IMProcessor processor : EncryptProvider.processors) {
|
||||
if ((processor.isUsed() || !processor.isPublic()) && processor.isEncrypted(msgBody) && (processor.isPublic() || EncryptProvider.getKeyForProcessor(processor, peer) != null))
|
||||
return "\uD83D\uDD12 " + injectOwnTextAll(processor.decode(msgBody, EncryptProvider.getKeyForProcessor(processor, peer)));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return injectOwnTextAll(msgBody);
|
||||
}
|
||||
|
||||
// This will use only the processor which was chosen in chat menu
|
||||
public static String encryptMessage(MsgFromUser msg) {
|
||||
String msgBody = EncryptProvider.getBody(msg);
|
||||
|
||||
Log.d("EncryptProvider", "encryptMessage: msg = " + msg);
|
||||
Log.d("EncryptProvider", "encryptMessage: body = " + msgBody);
|
||||
Log.d("EncryptProvider", "encryptMessage: peerId = " + EncryptProvider.getPeerId(msg));
|
||||
|
||||
for (IMProcessor processor : EncryptProvider.processors) {
|
||||
int peer = EncryptProvider.getPeerId(msg);
|
||||
if (processor.isUsedToEncrypt(peer)) {
|
||||
return injectOwnText(processor.encode(msgBody, EncryptProvider.getKeyForProcessor(processor, peer)));
|
||||
}
|
||||
}
|
||||
|
||||
return injectOwnText(msgBody);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.getString;
|
||||
import static ru.vtosters.lite.ui.components.FragAnimationKit.setAnimations;
|
||||
import static ru.vtosters.lite.utils.Preferences.getString;
|
||||
|
||||
public class FragAnimationHook {
|
||||
public static boolean animateOpen(FragmentTransaction transaction) {
|
||||
+4
-8
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.os.Build;
|
||||
import android.util.Base64;
|
||||
@@ -15,15 +15,12 @@ import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static ru.vtosters.lite.utils.Preferences.isValidSignature;
|
||||
import static ru.vtosters.hooks.other.Preferences.isValidSignature;
|
||||
|
||||
|
||||
public class GcmHook {
|
||||
|
||||
private static final String agent = String.format("Android-GCM/1.5 (%s %s)", Build.MODEL, Build.MODEL);
|
||||
|
||||
private static KeyPair pair;
|
||||
|
||||
private static int rid = 0;
|
||||
|
||||
static {
|
||||
@@ -35,15 +32,15 @@ public class GcmHook {
|
||||
}
|
||||
|
||||
public static String requestToken(String orig) {
|
||||
return "yssp9o9p9pamz5t-nvmq8spgwtin3e0==";
|
||||
return isValidSignature() ? "yssp9o9p9pamz5t-nvmq8spgwtin3e0==" : requestToken();
|
||||
}
|
||||
|
||||
public static String requestToken() {
|
||||
String xappide;
|
||||
try {
|
||||
String aid = getRandomAid();
|
||||
String pub2 = genNewKey();
|
||||
String sig = getSig(pub2);
|
||||
String xappide;
|
||||
try {
|
||||
byte[] bytes = MessageDigest.getInstance("SHA1").digest(pair.getPublic().getEncoded());
|
||||
bytes[0] = (byte) (((bytes[0] & 15) + 112) & 255);
|
||||
@@ -200,7 +197,6 @@ public class GcmHook {
|
||||
}).getBytes(StandardCharsets.UTF_8));
|
||||
return Base64.encodeToString(sign.sign(), 0);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+17
-6
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
@@ -6,10 +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 GmsUtils {
|
||||
private static final boolean needToSpoof = !isGmsInstalled() && isFakeGmsInstalled();
|
||||
public class GmsHook {
|
||||
private static final boolean needToSpoof = !isGmsInstalled() && (isFakeGmsInstalled() || isFakeGms2Installed());
|
||||
|
||||
public static boolean isGmsInstalled() {
|
||||
try {
|
||||
@@ -29,8 +31,17 @@ public class GmsUtils {
|
||||
}
|
||||
} // 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() {
|
||||
@@ -44,7 +55,7 @@ public class GmsUtils {
|
||||
} // 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() {
|
||||
@@ -52,6 +63,6 @@ public class GmsUtils {
|
||||
}
|
||||
|
||||
public static Class getFirebaseInstanceIdReceiverClass() {
|
||||
return needToSpoof ? FirebaseInstanceIdReceiver2.class : FirebaseInstanceIdReceiver.class;
|
||||
return needToSpoof ? (isFakeGms2Installed() ? FirebaseInstanceIdReceiver3.class : FirebaseInstanceIdReceiver2.class) : FirebaseInstanceIdReceiver.class;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.feature.groupslist;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.util.Log;
|
||||
import org.json.JSONArray;
|
||||
@@ -0,0 +1,39 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
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 java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
|
||||
public class JsonInjectors {
|
||||
public static JSONObject menu(JSONObject orig) throws JSONException {
|
||||
return SuperAppUtils.menu(orig);
|
||||
}
|
||||
|
||||
public static JSONObject superapp(JSONObject json) throws JSONException {
|
||||
return SuperAppUtils.superapp(json);
|
||||
}
|
||||
|
||||
|
||||
public static JSONObject setOnlineInfo(JSONObject json) throws JSONException {
|
||||
return OnlineBypass.setOnlineInfo(json);
|
||||
}
|
||||
|
||||
public static JSONArray setOnlineInfoUsers(JSONArray profiles) throws JSONException {
|
||||
return OnlineBypass.setOnlineInfoUsers(profiles);
|
||||
}
|
||||
|
||||
public static JSONArray newsfeedlist(JSONArray items) throws JSONException {
|
||||
return NewsFeedFiltersUtils.newsfeedlist(items);
|
||||
}
|
||||
|
||||
public static JSONObject friends(JSONObject json) throws JSONException, ParseException, IOException {
|
||||
return FriendsCatalogUtils.inject(json);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import ru.vtosters.lite.music.LastFMScrobbler;
|
||||
|
||||
public class LastFMHook {
|
||||
public static void grabMusicTrack(MusicTrack musictrack) {
|
||||
LastFMScrobbler.grabMusicTrack(musictrack);
|
||||
}
|
||||
}
|
||||
+26
-8
@@ -1,32 +1,40 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import b.h.g.k.VKProgressDialog;
|
||||
import com.aefyr.tsg.g2.TelegramStickersService;
|
||||
import com.guardanis.applock.AppLock;
|
||||
import com.guardanis.applock.activities.UnlockActivity;
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
import ru.vtosters.hooks.ui.SystemThemeChangerHook;
|
||||
import ru.vtosters.lite.concurrent.VTExecutors;
|
||||
import ru.vtosters.lite.downloaders.notifications.NotificationChannels;
|
||||
import ru.vtosters.lite.hooks.ui.SystemThemeChangerHook;
|
||||
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;
|
||||
import ru.vtosters.lite.utils.*;
|
||||
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 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;
|
||||
import static ru.vtosters.lite.utils.Preferences.checkupdates;
|
||||
|
||||
public class MainActivityInjector {
|
||||
public static void inject(Activity activity) {
|
||||
SystemThemeChangerHook.themeOnStart(activity);
|
||||
sendRequest();
|
||||
UsersList.getUsersList();
|
||||
VTVerifications.load(activity);
|
||||
|
||||
if (checkupdates()) OTADialog.checkUpdates(activity);
|
||||
|
||||
@@ -40,12 +48,14 @@ public class MainActivityInjector {
|
||||
NotificationChannels.createChannels();
|
||||
}
|
||||
|
||||
if (Preferences.isNewBuild() && !ThemesUtils.isMonetTheme() && ThemesManager.canApplyCustomAccent() && ThemesUtils.useNewColorEngine()) {
|
||||
if (Preferences.isNewBuild()
|
||||
&& !ThemesUtils.isMonetTheme()
|
||||
&& ThemesManager.canApplyCustomAccent()) {
|
||||
Preferences.updateBuildNumber();
|
||||
updateBinsAndTmpArchive(activity);
|
||||
}
|
||||
|
||||
VTExecutors.getIoScheduler().a(DeletedMessagesHandler::reloadMessagesList); // ioScheduler
|
||||
VTExecutors.getIoScheduler().a(DeletedMessagesHook::reloadMessagesList); // ioScheduler
|
||||
|
||||
if (activity.getIntent().getAction() != null && Intent.ACTION_APPLICATION_PREFERENCES.equals(activity.getIntent().getAction())) {
|
||||
NavigatorUtils.switchToSettings(activity);
|
||||
@@ -54,8 +64,16 @@ 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);
|
||||
}
|
||||
|
||||
public static void applock(Activity activity) {
|
||||
if (AppLock.isUnlockRequired(activity)) {
|
||||
var intent = new Intent(activity, UnlockActivity.class);
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateBinsAndTmpArchive(Activity activity) {
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.dialogs;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import com.vk.im.engine.commands.messages.SetUserActivityCmd;
|
||||
import com.vk.im.engine.models.dialogs.Dialog;
|
||||
@@ -7,7 +7,7 @@ import ru.vtosters.lite.dialogs.helpers.DoNotTypeDBHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DNRModule {
|
||||
public class MessagesActivityHook {
|
||||
public static DoNotReadDBHelper mDoNotReadDBHelper = new DoNotReadDBHelper();
|
||||
public static DoNotTypeDBHelper mDoNotTypeDBHelper = new DoNotTypeDBHelper();
|
||||
|
||||
+11
-2
@@ -1,9 +1,12 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
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.lite.translators.BaseTranslator;
|
||||
import ru.vtosters.lite.ui.dialogs.MessageSettings;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
@@ -11,9 +14,9 @@ import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.*;
|
||||
import static ru.vtosters.lite.ui.dialogs.MessageSettings.bombCount;
|
||||
import static ru.vtosters.lite.ui.dialogs.MessageSettings.isSilentEnabled;
|
||||
import static ru.vtosters.lite.utils.Preferences.*;
|
||||
|
||||
public class MessagesHook {
|
||||
public static String injectOwnText(String oldText) {
|
||||
@@ -104,4 +107,10 @@ public class MessagesHook {
|
||||
default -> 0;
|
||||
};
|
||||
}
|
||||
|
||||
public static void reloadMessages() {
|
||||
ImEngineProvider.b().a();
|
||||
ImAudioMsgPlayerProvider.b().e(PlayerActionSources.a);
|
||||
ImAudioMsgPlayerProvider.b().d(PlayerActionSources.a);
|
||||
} // Delete and reload msg cache
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.PowerManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.vk.core.preference.Preference;
|
||||
import com.vk.discover.DiscoverItemDecorator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
|
||||
public class NewsfeedHook {
|
||||
public static long getUpdateNewsfeed(boolean refresh_timeout) {
|
||||
if (vkme()) {
|
||||
return MAX_VALUE;
|
||||
}
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
||||
public static boolean samsungFixRem(RecyclerView recyclerView, DiscoverItemDecorator discoverItemDecorator) {
|
||||
if (!recyclerView.isComputingLayout() && recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
recyclerView.removeItemDecoration(discoverItemDecorator);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean samsungFixAdd(RecyclerView recyclerView, DiscoverItemDecorator discoverItemDecorator) {
|
||||
if (!recyclerView.isComputingLayout() && recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
recyclerView.addItemDecoration(discoverItemDecorator);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static List hideElement(ArrayList list) {
|
||||
if (!getBoolValue("whatsnew", true)) {
|
||||
list.clear();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static String[] feedParams() {
|
||||
HashSet<String> params = new HashSet<>();
|
||||
params.add("post");
|
||||
params.add("photo");
|
||||
params.add("photo_tag");
|
||||
|
||||
if (!friendsrecomm()) {
|
||||
params.add("friends_recomm");
|
||||
}
|
||||
|
||||
if (!ads()) {
|
||||
params.add("app_widget");
|
||||
params.add("promo_button");
|
||||
}
|
||||
|
||||
if (!authorsrecomm()) {
|
||||
params.add("authors_rec");
|
||||
}
|
||||
|
||||
return params.toArray(new String[0]);
|
||||
}
|
||||
|
||||
public static void adsParams(HashSet<String> hashSet) {
|
||||
if (ads()) {
|
||||
hashSet.add("ads_disabled");
|
||||
} else {
|
||||
hashSet.add("ads_app_slider");
|
||||
hashSet.add("ads_site_slider");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
public static boolean isPowerSaveMode() {
|
||||
var pw = (PowerManager) getGlobalContext().getSystemService(Context.POWER_SERVICE);
|
||||
|
||||
// return !getBoolValue("force_disable_psm", false) && pw.isPowerSaveMode();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+15
-13
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.util.Log;
|
||||
import com.vtosters.lite.R;
|
||||
@@ -10,13 +10,11 @@ import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
|
||||
import static ru.vtosters.lite.hooks.JsonInjectors.setOnlineInfo;
|
||||
import static ru.vtosters.lite.hooks.JsonInjectors.setOnlineInfoUsers;
|
||||
import static ru.vtosters.hooks.other.Preferences.*;
|
||||
import static ru.vtosters.lite.net.Request.makeRequest;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
|
||||
import static ru.vtosters.lite.utils.Preferences.*;
|
||||
|
||||
public class OnlineFormatterHook {
|
||||
private static String AppName;
|
||||
@@ -71,6 +69,7 @@ public class OnlineFormatterHook {
|
||||
case 6614620 -> "Laney";
|
||||
case 5632485 -> "SpaceVK";
|
||||
case 6287487 -> "vk.com";
|
||||
case 8202606 -> "VK Me Web";
|
||||
case 4542624 -> "Black VK";
|
||||
case 3917910 -> "Miranda NG (bridge)";
|
||||
case 8043814 -> "Quise";
|
||||
@@ -117,7 +116,7 @@ public class OnlineFormatterHook {
|
||||
}
|
||||
|
||||
public static JSONObject onlineHook(JSONObject json) throws ParseException, IOException, JSONException {
|
||||
if (getBoolValue("onlinefix", false)) setOnlineInfo(json);
|
||||
if (getBoolValue("onlinefix", false)) JsonInjectors.setOnlineInfo(json);
|
||||
|
||||
return json;
|
||||
}
|
||||
@@ -126,7 +125,7 @@ public class OnlineFormatterHook {
|
||||
if (!getBoolValue("onlinefix", false)) return jsonArr;
|
||||
|
||||
try {
|
||||
setOnlineInfoUsers(jsonArr);
|
||||
JsonInjectors.setOnlineInfoUsers(jsonArr);
|
||||
} catch (Exception e) {
|
||||
Log.e("onlineHookProfiles", e.getMessage());
|
||||
}
|
||||
@@ -134,25 +133,27 @@ public class OnlineFormatterHook {
|
||||
return jsonArr;
|
||||
}
|
||||
|
||||
public static JSONObject onlineHookProfiles(JSONObject json) throws ParseException, IOException, JSONException {
|
||||
public static JSONObject onlineHookProfiles(JSONObject json) {
|
||||
if (!getBoolValue("onlinefix", false)) return json;
|
||||
|
||||
try {
|
||||
setOnlineInfoUsers(json.optJSONArray("profiles"));
|
||||
JsonInjectors.setOnlineInfoUsers(json.optJSONArray("profiles"));
|
||||
} catch (Exception e) {
|
||||
Log.e("onlineHookProfiles", e.getMessage());
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public static JSONObject onlineHookItems(JSONObject json) throws ParseException, IOException, JSONException {
|
||||
public static JSONObject onlineHookItems(JSONObject json) {
|
||||
if (!getBoolValue("onlinefix", false)) return json;
|
||||
|
||||
try {
|
||||
setOnlineInfoUsers(json.optJSONArray("items"));
|
||||
JsonInjectors.setOnlineInfoUsers(json.optJSONArray("items"));
|
||||
} catch (Exception e) {
|
||||
Log.e("onlineHookItems", e.getMessage());
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@@ -160,22 +161,23 @@ public class OnlineFormatterHook {
|
||||
if (!getBoolValue("onlinefix", false)) return json;
|
||||
|
||||
try {
|
||||
setOnlineInfoUsers(json.optJSONObject("read_requests").optJSONArray("items"));
|
||||
JsonInjectors.setOnlineInfoUsers(json.optJSONObject("read_requests").optJSONArray("items"));
|
||||
} catch (Exception e) {
|
||||
Log.e("onlineHookItems", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
setOnlineInfoUsers(json.optJSONObject("recommendations").optJSONArray("items"));
|
||||
JsonInjectors.setOnlineInfoUsers(json.optJSONObject("recommendations").optJSONArray("items"));
|
||||
} catch (Exception e) {
|
||||
Log.e("onlineHookItems", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
setOnlineInfoUsers(json.optJSONArray("profiles"));
|
||||
JsonInjectors.setOnlineInfoUsers(json.optJSONArray("profiles"));
|
||||
} catch (Exception e) {
|
||||
Log.e("onlineHookItems", e.getMessage());
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
import androidx.core.content.FileProvider;
|
||||
import com.vk.core.dialogs.actionspopup.ActionsPopup;
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
import com.vk.dto.common.AttachmentWithMedia;
|
||||
import com.vk.dto.common.ImageSize;
|
||||
import com.vtosters.lite.R;
|
||||
import com.vtosters.lite.attachments.DocumentAttachment;
|
||||
import com.vtosters.lite.attachments.PhotoAttachment;
|
||||
import okhttp3.*;
|
||||
import okio.Okio;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.lite.themes.utils.RecolorUtils;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
import ru.vtosters.lite.utils.SearchEngine;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class PhotoViewer {
|
||||
static OkHttpClient client = VtOkHttpClient.getInstance();
|
||||
|
||||
//region INSERTION INTO SMALI
|
||||
@SuppressLint("UseCompatLoadingForDrawables")
|
||||
public static void addMenuItems(AttachmentWithMedia attachment, ActionsPopup.b actionPopup, int i, boolean z) {
|
||||
actionPopup.a(
|
||||
R.string.copy,
|
||||
RecolorUtils.fixActionMenuIcons(R.drawable.ic_copy_outline_28),
|
||||
false,
|
||||
() -> {
|
||||
copyImage(attachment);
|
||||
return null;
|
||||
}
|
||||
).a(
|
||||
R.string.search_photo_content,
|
||||
RecolorUtils.fixActionMenuIcons(R.drawable.ic_menu_search_outline_28),
|
||||
false,
|
||||
() -> {
|
||||
searchImageWithUrl(attachment);
|
||||
return null;
|
||||
}
|
||||
).a(
|
||||
R.string.copy_photo_url_content,
|
||||
RecolorUtils.fixActionMenuIcons(R.drawable.ic_copy_outline_28),
|
||||
false,
|
||||
() -> {
|
||||
copyImageUrl(attachment);
|
||||
return null;
|
||||
}
|
||||
).a(
|
||||
R.string.open_original_photo_content,
|
||||
RecolorUtils.fixActionMenuIcons(R.drawable.ic_link_outline_28),
|
||||
false,
|
||||
() -> {
|
||||
openUrl(getImageUrlFromAttachment(attachment));
|
||||
return null;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressLint("NonConstantResourceId")
|
||||
public static boolean interceptClick(AttachmentWithMedia attachment, MenuItem item, View view) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.copy_image -> copyImage(attachment);
|
||||
case R.id.search_photo -> searchImageWithUrl(attachment);
|
||||
case R.id.copy_photo_url -> copyImageUrl(attachment);
|
||||
case R.id.open_original_photo -> openUrl(getImageUrlFromAttachment(attachment));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//endregion
|
||||
|
||||
private static void copyImage(AttachmentWithMedia attachment) {
|
||||
var req = new Request.a()
|
||||
.b(getImageUrlFromAttachment(attachment))
|
||||
.a();
|
||||
client.a(req).a(new Callback() {
|
||||
@Override
|
||||
public void a(Call call, IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(Call call, Response response)
|
||||
throws IOException {
|
||||
var tmpImage = new File(AndroidUtils.getGlobalContext().getExternalCacheDir(), attachment.getId() + ".jpg");
|
||||
try (var resp = client.a(req).execute();
|
||||
var sink = Okio.a(Okio.b(tmpImage))) {
|
||||
sink.a(resp.a().f());
|
||||
var manager = (ClipboardManager) AndroidUtils.getGlobalContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
var uri = FileProvider.getUriForFile(
|
||||
AndroidUtils.getGlobalContext(),
|
||||
"com.vtosters.lite.common.VKFileProvider",
|
||||
tmpImage);
|
||||
var data = ClipData.newUri(
|
||||
AndroidUtils.getGlobalContext().getContentResolver(),
|
||||
"image",
|
||||
uri);
|
||||
manager.setPrimaryClip(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void searchImageWithUrl(AttachmentWithMedia attachment) {
|
||||
String url = getImageUrlFromAttachment(attachment);
|
||||
if (TextUtils.isEmpty(url)) return;
|
||||
int selectedEngine = SearchEngine.getDefaultSearchEngine();
|
||||
if (selectedEngine < 0) {
|
||||
var items = new String[SearchEngine.values().length];
|
||||
for (int i = 0; i < SearchEngine.values().length; ++i)
|
||||
items[i] = SearchEngine.values()[i].mTitle;
|
||||
new VkAlertDialog.Builder(LifecycleUtils.getCurrentActivity())
|
||||
.setItems(items, (di, i) -> openUrl(SearchEngine.values()[i].buildSearchUrl(url)))
|
||||
.show();
|
||||
} else {
|
||||
// index correction for old versions with numeration "1-x"
|
||||
if (selectedEngine >= SearchEngine.values().length) SearchEngine.setDefaultSearchEngine(--selectedEngine);
|
||||
openUrl(SearchEngine.values()[selectedEngine].buildSearchUrl(url));
|
||||
}
|
||||
}
|
||||
|
||||
private static void copyImageUrl(AttachmentWithMedia attachment) {
|
||||
String url = getImageUrlFromAttachment(attachment);
|
||||
if (TextUtils.isEmpty(url)) return;
|
||||
ClipboardManager manager = (ClipboardManager) AndroidUtils.getGlobalContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
manager.setPrimaryClip(ClipData.newPlainText("vk_photo_url", url));
|
||||
Toast.makeText(AndroidUtils.getGlobalContext(), R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private static void openUrl(String url) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
Log.d("PhotoViewer", "url is null or empty");
|
||||
return;
|
||||
}
|
||||
var intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
AndroidUtils.getGlobalContext().startActivity(intent);
|
||||
}
|
||||
|
||||
private static String getImageUrlFromAttachment(AttachmentWithMedia attachment) {
|
||||
List<ImageSize> imageSizes;
|
||||
|
||||
if (attachment instanceof PhotoAttachment) {
|
||||
imageSizes = ((PhotoAttachment) attachment).D.Q.t1();
|
||||
} else if (attachment instanceof DocumentAttachment && ((DocumentAttachment) attachment).J != null) {
|
||||
imageSizes = ((DocumentAttachment) attachment).J.t1();
|
||||
} else {
|
||||
ToastUtils.a(R.string.photo_get_error);
|
||||
return "";
|
||||
}
|
||||
|
||||
if (imageSizes.isEmpty()) return "";
|
||||
|
||||
var max = imageSizes.get(0);
|
||||
for (int i = 1; i < imageSizes.size(); i++) {
|
||||
var tmp = imageSizes.get(i);
|
||||
if (max.t1() < tmp.t1()) max = tmp;
|
||||
}
|
||||
return max.url;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.graphics.*;
|
||||
import com.facebook.drawee.generic.RoundingParams;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.Preferences;
|
||||
|
||||
public class PicRoundingHook {
|
||||
private static final int pref = Preferences.getPreferences().getInt("pic_rounding", 0);
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -6,7 +6,7 @@ import android.widget.TextView;
|
||||
import com.vk.dto.polls.PollOption;
|
||||
import com.vk.polls.ui.views.PollOptionView;
|
||||
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
|
||||
public class PollHook {
|
||||
public static void show(PollOptionView view) {
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -6,7 +6,7 @@ import android.widget.RelativeLayout;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.vk.newsfeed.holders.BaseFooterHolder;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.lite.utils.Preferences;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
|
||||
public class PostViewHook {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import com.vk.core.dialogs.actionspopup.ActionsPopup;
|
||||
import com.vk.profile.ui.components.CommunityFragmentActionsMenuBuilder;
|
||||
import com.vk.profile.ui.components.ProfileFragmentActionsMenuBuilder;
|
||||
import ru.vtosters.lite.ui.vkui.MenuBuilder;
|
||||
|
||||
public class ProfileMenuHook {
|
||||
public static void inject(final CommunityFragmentActionsMenuBuilder mb, final ActionsPopup.b builder) {
|
||||
MenuBuilder.injectAP(mb, builder);
|
||||
}
|
||||
|
||||
public static void inject(final ProfileFragmentActionsMenuBuilder mb, final ActionsPopup.b builder) {
|
||||
MenuBuilder.injectAP(mb, builder);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
|
||||
public class PromoStickersHook {
|
||||
public static String hook() {
|
||||
+73
-3
@@ -1,7 +1,8 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.widget.RadioButton;
|
||||
@@ -10,18 +11,87 @@ import androidx.appcompat.view.ContextThemeWrapper;
|
||||
import com.vk.auth.ui.VkAuthTextView;
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.proxy.api.VikaMobile;
|
||||
import ru.vtosters.lite.ui.fragments.DataSettingsFragment;
|
||||
import ru.vtosters.lite.ui.fragments.ProxySettingsFragment;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.NavigatorUtils;
|
||||
import ru.vtosters.lite.utils.Preferences;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.getString;
|
||||
import static ru.vtosters.hooks.other.ThemesUtils.getTextAttr;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.*;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
|
||||
import static ru.vtosters.lite.utils.LifecycleUtils.restartApplication;
|
||||
import static ru.vtosters.lite.utils.ThemesUtils.getTextAttr;
|
||||
|
||||
public class ProxyHook {
|
||||
public static String linkReplacer(String link) {
|
||||
var vkapi = "api.vk.com";
|
||||
var oauth = "oauth.vk.com";
|
||||
var vkstatic = "static.vk.com";
|
||||
|
||||
var proxyapi = getString("proxyapi");
|
||||
var proxyoauth = getString("proxyoauth");
|
||||
var proxystatic = getString("proxystatic");
|
||||
|
||||
if (isVikaProxyEnabled()) {
|
||||
proxyapi = VikaMobile.getApiHost();
|
||||
proxyoauth = VikaMobile.getOauthHost();
|
||||
proxystatic = VikaMobile.getStaticHost();
|
||||
}
|
||||
|
||||
if (!isAnyProxyEnabled() || link.isEmpty()) {
|
||||
return link;
|
||||
}
|
||||
|
||||
if (proxyapi.isEmpty() || proxyoauth.isEmpty() || proxystatic.isEmpty()) {
|
||||
Log.d("VTLite", "Proxy is not set" + " " + proxyapi + " " + proxyoauth + " " + proxystatic);
|
||||
return link;
|
||||
}
|
||||
|
||||
if (link.contains(vkapi)) {
|
||||
return link.replaceAll(vkapi, proxyapi);
|
||||
}
|
||||
|
||||
if (link.contains(oauth)) {
|
||||
return link.replaceAll(oauth, proxyoauth);
|
||||
}
|
||||
|
||||
if (link.contains(vkstatic)) {
|
||||
return link.replaceAll(vkstatic, proxystatic);
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
public static String staticFix(String str) {
|
||||
var string = getString("proxystatic");
|
||||
|
||||
if (isVikaProxyEnabled()) {
|
||||
string = VikaMobile.getStaticHost();
|
||||
}
|
||||
|
||||
if (isAnyProxyEnabled() && !string.isEmpty()) {
|
||||
return str.replaceAll(string, "static.vk.com");
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
public static String getAwayPhpCom() {
|
||||
var proxyapi = getString("proxyapi");
|
||||
|
||||
if (isVikaProxyEnabled()) {
|
||||
proxyapi = VikaMobile.getApiHost();
|
||||
}
|
||||
|
||||
if (isAnyProxyEnabled() && !proxyapi.isEmpty()) {
|
||||
return proxyapi;
|
||||
}
|
||||
|
||||
return "m.vk.com";
|
||||
}
|
||||
|
||||
public static void hookAuth(View v) {
|
||||
VkAuthTextView button = v.findViewById(AndroidUtils.getIdentifier("already_have_account", "id"));
|
||||
button.setText(R.string.proxy_setup);
|
||||
@@ -0,0 +1,29 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class RenameHook {
|
||||
public static void injectIntoJson(JSONObject obj) throws JSONException {
|
||||
// int i = obj.getInt("id");
|
||||
// if (RenameTool.updateRequested) {
|
||||
// RenameTool.reloadDB();
|
||||
// }
|
||||
//
|
||||
// Pair<String, String> user = RenameTool.renamedUsers.get(i);
|
||||
// if (user == null) return;
|
||||
// obj.put(RenameTool.COLUMN_FIRSTNAME, user.first).put(RenameTool.COLUMN_LASTNAME, user.second);
|
||||
}
|
||||
|
||||
public static void injectIntoJsonGroup(JSONObject obj) throws JSONException {
|
||||
// int i = obj.getInt("id");
|
||||
//
|
||||
// if (RenameTool.updateRequested) {
|
||||
// RenameTool.reloadDB();
|
||||
// }
|
||||
//
|
||||
// String user = RenameTool.renamedGroups.get(i);
|
||||
// if (user == null) return;
|
||||
// obj.put("name", user);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import com.vk.im.engine.models.ProfilesSimpleInfo;
|
||||
import com.vk.im.engine.models.messages.MsgFromUser;
|
||||
import com.vk.im.engine.models.messages.NestedMsg;
|
||||
import com.vk.im.ui.views.ReplyView;
|
||||
|
||||
import static ru.vtosters.lite.encryption.EncryptProvider.decryptMessage;
|
||||
import static ru.vtosters.hooks.EncryptionMessagesHook.decryptMessage;
|
||||
|
||||
public class ReplyMsgHook {
|
||||
public static void injectWithDecrypt(ReplyView replyView, MsgFromUser msgFromUser, ProfilesSimpleInfo profilesSimpleInfo, boolean someBool) {
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.util.Log;
|
||||
import com.vk.api.internal.MethodCall;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import static ru.vtosters.lite.utils.Preferences.dev;
|
||||
import static ru.vtosters.hooks.other.Preferences.dev;
|
||||
|
||||
public class RequestDumper {
|
||||
public static void addParams(MethodCall.a paramslist, String method, LinkedHashMap<String, String> params, String apiver) {
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import com.vk.apps.AppsFragment;
|
||||
import com.vk.discover.DiscoverFragment;
|
||||
@@ -23,8 +23,8 @@ import com.vtosters.lite.fragments.y2.VideoCatalogFragment;
|
||||
import com.vtosters.lite.general.fragments.GamesFragment;
|
||||
import com.vtosters.lite.general.fragments.PhotosFragment;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.*;
|
||||
import static ru.vtosters.lite.ui.components.DockBarEditorManager.getInstance;
|
||||
import static ru.vtosters.lite.utils.Preferences.*;
|
||||
|
||||
public class StartFragmentHook {
|
||||
public static Class getStartFragment() {
|
||||
+6
-3
@@ -1,7 +1,6 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import static ru.vtosters.lite.utils.Preferences.adsstories;
|
||||
import static ru.vtosters.lite.utils.Preferences.stories;
|
||||
import static ru.vtosters.hooks.other.Preferences.*;
|
||||
|
||||
public class StoriesHook {
|
||||
public static String ads() {
|
||||
@@ -11,4 +10,8 @@ public class StoriesHook {
|
||||
public static boolean showstories() {
|
||||
return stories();
|
||||
}
|
||||
|
||||
public static boolean getStoriesRead() {
|
||||
return getBoolValue("read_s", false);
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
@@ -10,9 +10,9 @@ import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
import androidx.core.widget.CompoundButtonCompat;
|
||||
import com.vk.core.util.ColorUtils;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.Preferences;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
|
||||
import static com.vtosters.lite.R.color.*;
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import com.aefyr.tsg.g2.TelegramStickersPack;
|
||||
import com.aefyr.tsg.g2.TelegramStickersService;
|
||||
import com.vk.dto.common.Attachment;
|
||||
import com.vk.dto.stickers.StickerItem;
|
||||
import com.vk.dto.stickers.StickerStockItem;
|
||||
import com.vk.im.engine.models.attaches.Attach;
|
||||
import com.vtosters.lite.attachments.PendingGraffitiAttachment;
|
||||
import com.vtosters.lite.im.AppAttachToImAttachConverter;
|
||||
import com.vtosters.lite.upload.Upload;
|
||||
import ru.vtosters.lite.tgs.TGRoot;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
|
||||
public class TelegramStickersHook {
|
||||
public static StickerStockItem getPackBySticker(int stickerId) {
|
||||
if (stickerId < TGRoot.N) return null;
|
||||
int index = (stickerId - TGRoot.N) / 120;
|
||||
|
||||
TelegramStickersPack p = null;
|
||||
for (TelegramStickersPack p_ : TelegramStickersService.getInstance(AndroidUtils.getGlobalContext())
|
||||
.getActivePacksListReference()) {
|
||||
if (p_.index == index) {
|
||||
p = p_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (p == null) return null;
|
||||
|
||||
try {
|
||||
return TGRoot.toStickerPack(p);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Attachment processSticker(StickerItem item) {
|
||||
int id = item.getId();
|
||||
if (id < TGRoot.N) return null;
|
||||
|
||||
int index = (id - TGRoot.N) / 120;
|
||||
int stickerId = (id - TGRoot.N) % 120;
|
||||
|
||||
TelegramStickersPack pack = null;
|
||||
for (TelegramStickersPack p : TelegramStickersService.getInstance(getGlobalContext()).getActivePacksListReference()) {
|
||||
if (p.index == index) {
|
||||
pack = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String image = pack.getStickerFile(stickerId).getAbsolutePath();
|
||||
|
||||
Bitmap bm = BitmapFactory.decodeFile(image);
|
||||
int upid = Upload.a();
|
||||
TGRoot.pendingStickers.push(upid);
|
||||
|
||||
Attachment att = new PendingGraffitiAttachment(upid, 0, image, bm.getWidth(), bm.getHeight(), null);
|
||||
bm.recycle();
|
||||
|
||||
return att;
|
||||
}
|
||||
|
||||
public static void injectStickers(List<StickerStockItem> list) {
|
||||
try {
|
||||
List<TelegramStickersPack> packs = TelegramStickersService.getInstance(getGlobalContext()).getActivePacksListReference();
|
||||
for (int i = packs.size() - 1; i >= 0; i--)
|
||||
list.add(0, TGRoot.toStickerPack(packs.get(i)));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static Attach modifyStickerIM(int i, StickerItem stickerItem, String str) {
|
||||
if (stickerItem.getId() < 76820000) {
|
||||
return AppAttachToImAttachConverter.a.a(i, stickerItem, str);
|
||||
}
|
||||
return AppAttachToImAttachConverter.a.a(processSticker(stickerItem));
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -1,12 +1,12 @@
|
||||
package ru.vtosters.lite.ui.dialogs;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.app.Activity;
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.lite.utils.Preferences;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
|
||||
public class ThemeChanging {
|
||||
public class ThemeChangeDrawerHook {
|
||||
public static void changeTheme(Activity activity, float[] f) {
|
||||
if (Preferences.systemtheme()) {
|
||||
new VkAlertDialog.Builder(activity)
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import com.vk.medianative.MediaImageEncoder;
|
||||
import com.vk.toggle.FeatureManager;
|
||||
import com.vk.toggle.Features;
|
||||
|
||||
import static ru.vtosters.lite.utils.Preferences.*;
|
||||
import static ru.vtosters.hooks.other.Preferences.*;
|
||||
|
||||
public class TogglesHook {
|
||||
public static boolean shouldPatch(Features.Type feature) {
|
||||
@@ -0,0 +1,49 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.webkit.WebView;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
import ru.vtosters.lite.themes.ThemesCore;
|
||||
import ru.vtosters.lite.utils.WebViewColoringUtils;
|
||||
|
||||
import static android.util.Base64.encodeToString;
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
|
||||
public class VKUIHook {
|
||||
public static void inject(WebView webView) {
|
||||
debugWebView(webView);
|
||||
applyVKUIStyles(webView);
|
||||
}
|
||||
|
||||
private static void debugWebView(WebView webView) {
|
||||
if (Preferences.getBoolValue("__dbg_webview", false)) {
|
||||
WebView.setWebContentsDebuggingEnabled(true);
|
||||
webView.evaluateJavascript("if (!window.eruda) {let parent = document.head || document.documentElement; let script = parent.appendChild(document.createElement('script')); script.src = 'https://cdn.jsdelivr.net/npm/eruda'; script.onload = () => eruda.init();}", null);
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyVKUIStyles(WebView webView) {
|
||||
if (getBoolValue("VKUI_INJ", true) && webView != null && webView.getUrl() != null && !webView.getUrl().contains("static.vk.com/memories")) {
|
||||
if (!WebViewColoringUtils.isLoaded) {
|
||||
WebViewColoringUtils.load();
|
||||
}
|
||||
loadAndApplyCSS(webView);
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadAndApplyCSS(WebView webView) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (ThemesCore.isCachedAccents()) {
|
||||
sb.append("\n\n");
|
||||
sb.append(WebViewColoringUtils.loadedCSS);
|
||||
}
|
||||
|
||||
if (ThemesUtils.isAmoledTheme()) {
|
||||
sb.append("\n\n");
|
||||
sb.append(WebViewColoringUtils.loadedCSSAmoled);
|
||||
}
|
||||
|
||||
WebViewColoringUtils.inject(webView, encodeToString(sb.toString().getBytes(), 2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import com.vk.dto.common.VerifyInfo;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.utils.VTVerifications;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
|
||||
public class VerificationsHook {
|
||||
public static boolean isVerified(int id) {
|
||||
return VTVerifications.sVerifications.contains(id);
|
||||
}
|
||||
|
||||
public static boolean vtverif() {
|
||||
return getBoolValue("VT_Verification", true);
|
||||
}
|
||||
|
||||
public static boolean isVerified(JSONObject jSONObject) {
|
||||
if (jSONObject.optInt("verified", 0) == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!getBoolValue("VT_Verification", true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isVerified(VTVerifications.getId(jSONObject));
|
||||
}
|
||||
|
||||
public static boolean hasPrometheus(JSONObject jSONObject) {
|
||||
if (jSONObject.optInt("trending", 0) == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!getBoolValue("VT_Fire", true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return VTVerifications.isPrometheus(VTVerifications.getId(jSONObject));
|
||||
}
|
||||
|
||||
public static boolean hasDeveloper(JSONObject jSONObject) {
|
||||
if (!getBoolValue("VT_Dev", true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return VTVerifications.isDeveloper(VTVerifications.getId(jSONObject));
|
||||
}
|
||||
|
||||
public static VerifyInfo VerifyInfo(JSONObject jSONObject) {
|
||||
return new VerifyInfo(isVerified(jSONObject), hasPrometheus(jSONObject));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import com.vk.dto.common.VideoFile;
|
||||
import ru.vtosters.lite.utils.ExternalLinkParser;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.isEnableExternalOpening;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
|
||||
public class VideoPlayerHook {
|
||||
public static boolean parseVideoFile(VideoFile file) {
|
||||
return ExternalLinkParser.parseVideoFile(file, getGlobalContext(), isEnableExternalOpening());
|
||||
}
|
||||
|
||||
public static boolean parseVideoFile(VideoFile file, Context context) {
|
||||
return ExternalLinkParser.parseVideoFile(file, context, isEnableExternalOpening());
|
||||
}
|
||||
|
||||
public static boolean parseVideoFile(VideoFile file, Activity activity) {
|
||||
return ExternalLinkParser.parseVideoFile(file, activity, isEnableExternalOpening());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
|
||||
public class VoiceMessagesHook {
|
||||
public static boolean getVoiceListened() {
|
||||
return getBoolValue("listen_v", false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import com.vk.im.engine.h;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
|
||||
import static ru.vtosters.lite.ui.wallpapers.WallpapersHooks.getWallpaper;
|
||||
import static ru.vtosters.lite.ui.wallpapers.WallpapersHooks.hasWallpapers;
|
||||
|
||||
public class WallpapersHooks {
|
||||
public static void setBg(View view) {
|
||||
if (hasWallpapers()) {
|
||||
((ImageView) view).setImageDrawable(getWallpaper()); // set picture to background
|
||||
} else {
|
||||
view.setBackgroundColor(ThemesUtils.getColorFromAttr(h.im_bg_chat)); // set default bg color
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-7
@@ -1,21 +1,18 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import com.vk.api.base.ApiConfig;
|
||||
import com.vk.core.preference.Preference;
|
||||
import com.vk.core.ui.themes.VKThemeHelper;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.proxy.api.ApiProxy;
|
||||
|
||||
public class WebAppUtils {
|
||||
|
||||
public class WebAppHook {
|
||||
public static JSONObject getWebAppConfig() throws JSONException {
|
||||
JSONObject jSONObject = new JSONObject()
|
||||
return new JSONObject()
|
||||
.put("scheme", VKThemeHelper.l().b())
|
||||
.put("app", "vkclient")
|
||||
.put("app_id", ApiConfig.a)
|
||||
.put("appearance", VKThemeHelper.l().a() ? "light" : "dark")
|
||||
.put("api_host", ApiProxy.linkReplacer(Preference.a().getString("apiHost", "api.vk.com")));
|
||||
return jSONObject;
|
||||
.put("api_host", ProxyHook.linkReplacer(Preference.a().getString("apiHost", "api.vk.com")));
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
package ru.vtosters.lite.hooks;
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.lite.utils.ThemesUtils;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
|
||||
import static ru.vtosters.lite.utils.Preferences.wbios;
|
||||
import static ru.vtosters.hooks.other.Preferences.wbios;
|
||||
|
||||
public class WritebarHook {
|
||||
public static int getWriteBar() {
|
||||
+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;
|
||||
+15
-33
@@ -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.lite.music.cache.CacheDatabaseDelegate.isCached;
|
||||
import static ru.vtosters.lite.music.cache.CacheDatabaseDelegate.isVkxCached;
|
||||
import static ru.vtosters.hooks.other.Preferences.milkshake;
|
||||
import static ru.vtosters.lite.utils.NetworkUtils.isNetworkConnected;
|
||||
import static ru.vtosters.lite.utils.Preferences.milkshake;
|
||||
|
||||
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;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user