Compare commits
30
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45f7cc4484 | ||
|
|
886ddd60c1 | ||
|
|
adc06426ac | ||
|
|
62aa568599 | ||
|
|
f2ac845797 | ||
|
|
a85e55a594 | ||
|
|
e2775db4e5 | ||
|
|
589e8928a0 | ||
|
|
cd189b1dda | ||
|
|
14c111a3e6 | ||
|
|
b506c56346 | ||
|
|
bbbc94e510 | ||
|
|
8cb2c380e7 | ||
|
|
b9879f9ed7 | ||
|
|
cf05e051e8 | ||
|
|
963c4d81ba | ||
|
|
099c699702 | ||
|
|
1117fc19d4 | ||
|
|
78dca26063 | ||
|
|
f5180f61d5 | ||
|
|
540fffdcc9 | ||
|
|
5357c60eaa | ||
|
|
c59f29121f | ||
|
|
bd38cab377 | ||
|
|
0058431590 | ||
|
|
bf4cf2be53 | ||
|
|
aac86a9952 | ||
|
|
ae00e72bac | ||
|
|
fea984f6fd | ||
|
|
d870c2f984 |
+2
-2
@@ -91,8 +91,8 @@ task testClasses {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.microsoft.appcenter:appcenter-analytics:5.0.1'
|
||||
implementation 'com.microsoft.appcenter:appcenter-crashes:5.0.1'
|
||||
implementation 'com.microsoft.appcenter:appcenter-analytics:5.0.2'
|
||||
implementation 'com.microsoft.appcenter:appcenter-crashes:5.0.2'
|
||||
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'
|
||||
|
||||
Vendored
+1
-2
@@ -43,5 +43,4 @@
|
||||
|
||||
-keep class com.vtosters.lite.** { *; }
|
||||
-keep class com.vk.** { *; }
|
||||
-keep class bruhcollective.itaysonlab.libvkx.client.** { *; }
|
||||
-keep class com.guardanis.applock.** { *; }
|
||||
-keep class bruhcollective.itaysonlab.libvkx.client.** { *; }
|
||||
@@ -36,8 +36,8 @@ public class TelegramStickersPack extends CustomStickersPack {
|
||||
public HashMap<String, List<Integer>> emojis = new HashMap<>();
|
||||
|
||||
public TelegramStickersPack(String id) {
|
||||
this.id=this.title=id;
|
||||
this.hash=id.hashCode();
|
||||
this.id = this.title = id;
|
||||
this.hash = id.hashCode();
|
||||
}
|
||||
|
||||
public JSONObject encodeEmojis() throws JSONException {
|
||||
|
||||
@@ -26,19 +26,13 @@ import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
public class TelegramStickersService {
|
||||
private static final String TAG = "TGStickersService";
|
||||
private static TelegramStickersService instance;
|
||||
|
||||
private final Context c;
|
||||
|
||||
private final ArrayList<TelegramStickersPack> packs;
|
||||
private final ArrayList<TelegramStickersPack> activePacks;
|
||||
private final ArrayList<TelegramStickersPack> inactivePacks;
|
||||
private final ArrayList<StickersEventsListener> listeners;
|
||||
private final HashSet<String> currentlyDownloading;
|
||||
|
||||
private final Handler uiThreadHandler;
|
||||
|
||||
private final TelegramStickersGrabber grabber;
|
||||
|
||||
private final TelegramStickersDbHelper dbHelper;
|
||||
private final ArrayList<Runnable> queuedTasks;
|
||||
private final ThreadPoolExecutor executor;
|
||||
@@ -48,16 +42,14 @@ public class TelegramStickersService {
|
||||
private TelegramStickersService(Context context) {
|
||||
instance = this;
|
||||
|
||||
this.c = context.getApplicationContext();
|
||||
|
||||
listeners = new ArrayList<>();
|
||||
currentlyDownloading = new HashSet<>();
|
||||
uiThreadHandler = new Handler(Looper.getMainLooper());
|
||||
grabber = new TelegramStickersGrabber(null);
|
||||
dbHelper = new TelegramStickersDbHelper(c);
|
||||
dbHelper = new TelegramStickersDbHelper(context);
|
||||
queuedTasks = new ArrayList<>();
|
||||
executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
|
||||
notificationsHelper = new NotificationsHelper(c);
|
||||
notificationsHelper = new NotificationsHelper(context);
|
||||
|
||||
packs = new ArrayList<>();
|
||||
activePacks = new ArrayList<>();
|
||||
@@ -70,11 +62,11 @@ public class TelegramStickersService {
|
||||
return instance == null ? new TelegramStickersService(c) : instance;
|
||||
}
|
||||
|
||||
private void updatePacks(final boolean notify) {
|
||||
private void updatePacks(boolean notify) {
|
||||
packs.clear();
|
||||
dbHelper.getAllPacks(new TelegramStickersDbHelper.PacksLoadingListener() {
|
||||
@Override
|
||||
public void onPackLoaded(final TelegramStickersPack pack) {
|
||||
public void onPackLoaded(TelegramStickersPack pack) {
|
||||
runOnUiThread(() -> {
|
||||
packs.add(pack);
|
||||
|
||||
@@ -103,14 +95,6 @@ public class TelegramStickersService {
|
||||
});
|
||||
}
|
||||
|
||||
public void addStickersEventsListener(StickersEventsListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeStickersEventsListener(StickersEventsListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
private void notifyPackAdded(TelegramStickersPack pack, int atIndex) {
|
||||
getGlobalContext().sendBroadcast(new Intent(StickersFragment.ACTION_RELOAD));
|
||||
if (listeners.isEmpty())
|
||||
@@ -188,20 +172,16 @@ public class TelegramStickersService {
|
||||
return inactivePacks;
|
||||
}
|
||||
|
||||
public boolean isDoneLoading() {
|
||||
return ready;
|
||||
}
|
||||
|
||||
public boolean requestPackDownload(final String id, File packFolder) {
|
||||
public void requestPackDownload(String id, File packFolder) {
|
||||
if (currentlyDownloading.contains(id)) {
|
||||
Log.e(TAG, String.format("Got request to download pack %s which is already downloading", id));
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ready) {
|
||||
final File folder = packFolder;
|
||||
File folder = packFolder;
|
||||
queuedTasks.add(() -> requestPackDownload(id, folder));
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
TelegramStickersPack pack = new TelegramStickersPack(id);
|
||||
@@ -221,85 +201,86 @@ public class TelegramStickersService {
|
||||
notifyPackAdded(pack, packs.size() - 1);
|
||||
}
|
||||
|
||||
final TelegramStickersPack newPack = pack;
|
||||
final boolean isUpdate = update;
|
||||
TelegramStickersPack newPack = pack;
|
||||
boolean isUpdate = update;
|
||||
|
||||
currentlyDownloading.add(id);
|
||||
notificationsHelper.packStartedDownloading(newPack);
|
||||
|
||||
|
||||
grabber.enableProxy();
|
||||
grabber.grabPack(id, packFolder, pack.version, new TelegramStickersGrabber.PackDownloadListener() {
|
||||
@Override
|
||||
public void onPackDownloaded(TelegramStickersPackInfo packInfo, boolean newVersionFound) {
|
||||
|
||||
runOnUiThread(() -> {
|
||||
newPack.state = TelegramStickersPack.DOWNLOADED;
|
||||
notifyPackChanged(newPack, packs.indexOf(newPack));
|
||||
currentlyDownloading.remove(newPack.id);
|
||||
syncPack(newPack);
|
||||
|
||||
if (isUpdate) {
|
||||
if (newPack.enabled)
|
||||
notifyActivePacksListChanged();
|
||||
} else {
|
||||
activePacks.add(newPack);
|
||||
notifyActivePacksListChanged();
|
||||
}
|
||||
});
|
||||
notificationsHelper.packDoneDownloading(newPack, true, isUpdate, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackDownloadError(final Exception e) {
|
||||
runOnUiThread(() -> {
|
||||
Log.e(TAG, "Error while downloading pack " + newPack.id);
|
||||
e.printStackTrace();
|
||||
|
||||
if (!isUpdate) {
|
||||
int index = packs.indexOf(newPack);
|
||||
packs.remove(index);
|
||||
notifyPackRemoved(newPack, index);
|
||||
} else {
|
||||
// try-catch block to handle possible timeout exception
|
||||
try {
|
||||
grabber.grabPack(id, packFolder, pack.version, new TelegramStickersGrabber.PackDownloadListener() {
|
||||
@Override
|
||||
public void onPackDownloaded(TelegramStickersPackInfo packInfo, boolean newVersionFound) {
|
||||
runOnUiThread(() -> {
|
||||
newPack.state = TelegramStickersPack.DOWNLOADED;
|
||||
notifyPackChanged(newPack, packs.indexOf(newPack));
|
||||
}
|
||||
currentlyDownloading.remove(newPack.id);
|
||||
syncPack(newPack);
|
||||
|
||||
notifyPackDownloadError(newPack, e);
|
||||
currentlyDownloading.remove(newPack.id);
|
||||
});
|
||||
notificationsHelper.packDoneDownloading(newPack, false, isUpdate, e);
|
||||
}
|
||||
if (isUpdate) {
|
||||
if (newPack.enabled)
|
||||
notifyActivePacksListChanged();
|
||||
} else {
|
||||
activePacks.add(newPack);
|
||||
notifyActivePacksListChanged();
|
||||
}
|
||||
});
|
||||
notificationsHelper.packDoneDownloading(newPack, true, isUpdate, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGotPackInfo(final TelegramStickersPackInfo packInfo) {
|
||||
runOnUiThread(() -> {
|
||||
newPack.title = packInfo.title;
|
||||
newPack.stickersCount = packInfo.stickersCount;
|
||||
newPack.version = packInfo.version;
|
||||
notifyPackChanged(newPack, packs.indexOf(newPack));
|
||||
});
|
||||
@Override
|
||||
public void onPackDownloadError(Exception e) {
|
||||
runOnUiThread(() -> {
|
||||
Log.e(TAG, "Error while downloading pack " + newPack.id);
|
||||
e.printStackTrace();
|
||||
|
||||
notificationsHelper.packDownloadUpdated(newPack, 0);
|
||||
}
|
||||
if (!isUpdate) {
|
||||
int index = packs.indexOf(newPack);
|
||||
packs.remove(index);
|
||||
notifyPackRemoved(newPack, index);
|
||||
} else {
|
||||
newPack.state = TelegramStickersPack.DOWNLOADED;
|
||||
notifyPackChanged(newPack, packs.indexOf(newPack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStickerDownloaded(String pack, File sticker, String boundEmoji, int stickerIndex, int downloadedStickersCount, int totalStickersCount) {
|
||||
stickerIndex--;
|
||||
notifyPackDownloadError(newPack, e);
|
||||
currentlyDownloading.remove(newPack.id);
|
||||
});
|
||||
notificationsHelper.packDoneDownloading(newPack, false, isUpdate, e);
|
||||
}
|
||||
|
||||
List<Integer> list = newPack.emojis.get(boundEmoji);
|
||||
if (list == null) list = new ArrayList<>();
|
||||
list.add(stickerIndex);
|
||||
newPack.emojis.put(boundEmoji, list);
|
||||
@Override
|
||||
public void onGotPackInfo(TelegramStickersPackInfo packInfo) {
|
||||
runOnUiThread(() -> {
|
||||
newPack.title = packInfo.title;
|
||||
newPack.stickersCount = packInfo.stickersCount;
|
||||
newPack.version = packInfo.version;
|
||||
notifyPackChanged(newPack, packs.indexOf(newPack));
|
||||
});
|
||||
|
||||
notificationsHelper.packDownloadUpdated(newPack, downloadedStickersCount);
|
||||
}
|
||||
});
|
||||
notificationsHelper.packDownloadUpdated(newPack, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
@Override
|
||||
public void onStickerDownloaded(String pack, File sticker, String boundEmoji, int stickerIndex, int downloadedStickersCount, int totalStickersCount) {
|
||||
stickerIndex--;
|
||||
|
||||
List<Integer> list = newPack.emojis.get(boundEmoji);
|
||||
if (list == null) list = new ArrayList<>();
|
||||
list.add(stickerIndex);
|
||||
newPack.emojis.put(boundEmoji, list);
|
||||
|
||||
notificationsHelper.packDownloadUpdated(newPack, downloadedStickersCount);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
// handle other possible exceptions
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void setPackEnabled(final TelegramStickersPack pack, final boolean enabled, final boolean notify) {
|
||||
public void setPackEnabled(TelegramStickersPack pack, boolean enabled, boolean notify) {
|
||||
if (!ready) {
|
||||
queuedTasks.add(() -> setPackEnabled(pack, enabled, notify));
|
||||
return;
|
||||
@@ -325,7 +306,7 @@ public class TelegramStickersService {
|
||||
}
|
||||
}
|
||||
|
||||
public void deletePack(final TelegramStickersPack pack) {
|
||||
public void deletePack(TelegramStickersPack pack) {
|
||||
if (!ready) {
|
||||
queuedTasks.add(() -> deletePack(pack));
|
||||
return;
|
||||
@@ -334,7 +315,6 @@ public class TelegramStickersService {
|
||||
boolean d = dbHelper.deletePack(pack);
|
||||
Log.d(TAG, "Delete from DB=" + d);
|
||||
|
||||
|
||||
int index = packs.indexOf(pack);
|
||||
packs.remove(index);
|
||||
notifyPackRemoved(pack, index);
|
||||
@@ -355,7 +335,7 @@ public class TelegramStickersService {
|
||||
uiThreadHandler.post(r);
|
||||
}
|
||||
|
||||
private void syncPack(final TelegramStickersPack pack) {
|
||||
private void syncPack(TelegramStickersPack pack) {
|
||||
if (!ready) {
|
||||
queuedTasks.add(() -> syncPack(pack));
|
||||
return;
|
||||
@@ -397,6 +377,4 @@ public class TelegramStickersService {
|
||||
|
||||
void onInactivePacksListChanged();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -7,23 +7,20 @@ import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import com.aefyr.tsg.g2.stickersgrabber.util.Flag;
|
||||
import com.aefyr.tsg.g2.stickersgrabber.util.GoalCounter;
|
||||
import okhttp3.*;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.net.*;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.net.Proxy;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
@@ -31,14 +28,19 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
*/
|
||||
public class TelegramStickersGrabber {
|
||||
private static final String TAG = "TSG";
|
||||
public static String REAL_TG_IP = null;
|
||||
public static String PROXY_IP = null;
|
||||
public static int PROXY_PORT = -1;
|
||||
public static String PROXY_USER = null;
|
||||
public static String PROXY_PASS = null;
|
||||
public static boolean PROXY_SOCKS = true;
|
||||
public static boolean HAS_PASS = false;
|
||||
public static boolean USE_PROXY = false;
|
||||
private static final OkHttpClient sClient = VtOkHttpClient.getInstance();
|
||||
private static final int MAX_RETRIES = 2;
|
||||
private static final AtomicInteger retryCount = new AtomicInteger();
|
||||
private static final int STICKER_QUALITY = 100;
|
||||
private static final String STICKER_FILE_NAME_FORMAT = "%03d.png";
|
||||
private static final String STICKERS_KEY = "stickers";
|
||||
private static final String FILE_ID_KEY = "file_id";
|
||||
private static final String EMOJI_KEY = "emoji";
|
||||
private static final String IS_ANIMATED_KEY = "is_animated";
|
||||
private static final String IS_VIDEO_KEY = "is_video";
|
||||
private static final String THUMB_KEY = "thumb";
|
||||
private static final String NAME_KEY = "name";
|
||||
private static final String TITLE_KEY = "title";
|
||||
private static String BOT_API_BASE_URL;
|
||||
private static String GET_STICKER_SET_URL;
|
||||
private static String GET_FILE_URL;
|
||||
@@ -50,12 +52,10 @@ public class TelegramStickersGrabber {
|
||||
|
||||
private final MessageDigest sha256;
|
||||
private final Handler uiThreadHandler;
|
||||
private String botApiKey = "";
|
||||
private NetClient httpClient;
|
||||
private String botApiKey;
|
||||
|
||||
public TelegramStickersGrabber(String botApiKey) {
|
||||
this.botApiKey = botApiKey;
|
||||
httpClient = new NetClient.Builder().connectTimeout(5, TimeUnit.SECONDS).build();
|
||||
uiThreadHandler = new Handler(Looper.getMainLooper());
|
||||
try {
|
||||
sha256 = MessageDigest.getInstance("SHA-256");
|
||||
@@ -69,81 +69,12 @@ public class TelegramStickersGrabber {
|
||||
public static void updateURLs() {
|
||||
BOT_API_BASE_FILE_URL = "https://api.telegram.org/file/bot%s/%s";
|
||||
|
||||
|
||||
BOT_API_BASE_URL = REAL_TG_IP != null ? "https://" + REAL_TG_IP + "/bot%s/" : "https://api.telegram.org/bot%s/";
|
||||
BOT_API_BASE_URL = "https://api.telegram.org/bot%s/";
|
||||
GET_STICKER_SET_URL = BOT_API_BASE_URL + "getStickerSet?name=%s";
|
||||
GET_FILE_URL = BOT_API_BASE_URL + "getFile?file_id=%s";
|
||||
}
|
||||
|
||||
public static boolean isTelegramBlocked() {
|
||||
NetClient client = new NetClient.Builder().connectTimeout(5, TimeUnit.SECONDS).build();
|
||||
try {
|
||||
if (PROXY_IP != null) {
|
||||
Socket socket = new Socket(PROXY_IP, PROXY_PORT);
|
||||
Proxy proxy = new Proxy(Proxy.Type.SOCKS, socket.getRemoteSocketAddress());
|
||||
NetClient.Builder b = new NetClient.Builder().proxy(proxy);
|
||||
if (PROXY_USER != null) {
|
||||
b = b.proxyAuthenticator(new PasswordAuthentication(PROXY_USER, PROXY_PASS.toCharArray()));
|
||||
}
|
||||
client = b.build();
|
||||
socket.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
NetRequest req = new NetRequest.Builder().url(REAL_TG_IP != null ? "https://" + REAL_TG_IP + "/test/" : "https://api.telegram.org/test/").build();
|
||||
try {
|
||||
NetResponse res = client.newCall(req).execute();
|
||||
String s = res.getDataString();
|
||||
|
||||
if (!s.equals("{\"ok\":false,\"error_code\":404,\"description\":\"Not Found\"}"))
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void resetProxy() {
|
||||
httpClient = new NetClient.Builder().connectTimeout(5, TimeUnit.SECONDS).build();
|
||||
}
|
||||
|
||||
public void enableProxy() {
|
||||
Thread kostil = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (PROXY_IP != null) {
|
||||
Socket socket = new Socket(PROXY_IP, PROXY_PORT);
|
||||
Proxy proxy = new Proxy(Proxy.Type.SOCKS, socket.getRemoteSocketAddress());
|
||||
NetClient.Builder b = httpClient.newBuilder().proxy(proxy);
|
||||
|
||||
if (PROXY_USER != null) {
|
||||
httpClient = b.proxyAuthenticator(new PasswordAuthentication(PROXY_USER, PROXY_PASS.toCharArray())).build();
|
||||
}
|
||||
|
||||
httpClient = b.build();
|
||||
socket.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
kostil.start();
|
||||
try {
|
||||
kostil.join();
|
||||
Log.d(TAG, "Proxy set");
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Unable to set proxy:");
|
||||
e.printStackTrace();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void grabPack(String id, File packFolder, String installedVersion, final PackDownloadListener listener) {
|
||||
public void grabPack(String id, File packFolder, String installedVersion, PackDownloadListener listener) {
|
||||
getPackInfo(id, packFolder, installedVersion, listener);
|
||||
}
|
||||
|
||||
@@ -151,264 +82,247 @@ public class TelegramStickersGrabber {
|
||||
botApiKey = key;
|
||||
}
|
||||
|
||||
public void checkKey(final KeyCheckListener listener) {
|
||||
public void checkKey(KeyCheckListener listener) {
|
||||
Log.d(TAG, "Checking key: " + botApiKey);
|
||||
NetRequest request = new NetRequest.Builder().get().url(String.format(BOT_API_BASE_URL + "getMe", botApiKey)).build();
|
||||
httpClient.newCall(request).enqueue(new NetCallback() {
|
||||
// Create a request object with the URL and bot API key
|
||||
Request request = new Request.a()
|
||||
.b(String.format(BOT_API_BASE_URL + "getMe", botApiKey))
|
||||
.a();
|
||||
// Create a new call object and enqueue it to run asynchronously
|
||||
sClient.a(request).a(new Callback() {
|
||||
@Override
|
||||
public void onFailure(NetCall call, IOException e) {
|
||||
e.printStackTrace();
|
||||
public void a(Call call, IOException e) {
|
||||
// Handle the failure case
|
||||
Log.d(TAG, e.getMessage());
|
||||
runOnUiThread(listener::onNetError);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(NetCall call, final NetResponse response) throws IOException {
|
||||
runOnUiThread(() -> listener.onKeyChecked(response.code() == 200));
|
||||
public void a(Call call, Response response) {
|
||||
Log.d(TAG, response.toString());
|
||||
runOnUiThread(() -> listener.onKeyChecked(response.h()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void getPackInfo(final String packName, final File packFolder, final String installedVersion, final PackDownloadListener listener) {
|
||||
NetRequest packInfoRequest = new NetRequest.Builder().get().url(String.format(GET_STICKER_SET_URL, botApiKey, packName)).build();
|
||||
httpClient.newCall(packInfoRequest).enqueue(new NetCallback() {
|
||||
private void getPack(StickerSet set, File packFolder, TelegramStickersPackInfo packInfo, PackDownloadListener listener) {
|
||||
GoalCounter downloadedStickers = new GoalCounter(set.stickers.size(), () -> {
|
||||
Log.d(TAG, String.format("Pack %s has been downloaded to %s", set.id, packFolder.getAbsolutePath()));
|
||||
listener.onPackDownloaded(packInfo, true);
|
||||
});
|
||||
|
||||
Flag deathFlag = new Flag();
|
||||
|
||||
for (int i = 0; i < set.stickers.size(); i++) {
|
||||
Sticker sticker = set.stickers.get(i);
|
||||
String getFileUrl = String.format(GET_FILE_URL, botApiKey, sticker.fileId);
|
||||
Request fileInfoRequest = new Request.a()
|
||||
.b(getFileUrl)
|
||||
.a();
|
||||
|
||||
int stickerIndex = i + 1;
|
||||
|
||||
sClient.a(fileInfoRequest).a(new Callback() {
|
||||
@Override
|
||||
public void a(Call call, IOException e) {
|
||||
handleFailure(deathFlag, listener, e, downloadedStickers, call, fileInfoRequest, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(Call call, Response response) {
|
||||
if (deathFlag.up())
|
||||
return;
|
||||
|
||||
if (!response.h()) {
|
||||
retryRequest(call, fileInfoRequest, this);
|
||||
return;
|
||||
}
|
||||
|
||||
try (ResponseBody responseBody = response.a()) {
|
||||
JSONObject fileInfoResponse = new JSONObject(responseBody.g()).getJSONObject("result");
|
||||
String filePath = fileInfoResponse.getString("file_path");
|
||||
|
||||
if (botApiKey == null) botApiKey = "";
|
||||
|
||||
String fileDownloadUrl = String.format(BOT_API_BASE_FILE_URL, botApiKey, filePath);
|
||||
Request fileDownloadRequest = new Request.a()
|
||||
.b(fileDownloadUrl)
|
||||
.a();
|
||||
|
||||
sClient.a(fileDownloadRequest).a(new Callback() {
|
||||
@Override
|
||||
public void a(Call call, IOException e) {
|
||||
handleFailure(deathFlag, listener, e, downloadedStickers, call, fileDownloadRequest, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(Call call, Response response) {
|
||||
if (deathFlag.up())
|
||||
return;
|
||||
|
||||
if (!response.h()) {
|
||||
retryRequest(call, fileDownloadRequest, this);
|
||||
return;
|
||||
}
|
||||
|
||||
try (ResponseBody responseBody = response.a()) {
|
||||
if (responseBody == null) {
|
||||
handleFailure(deathFlag, listener, new TSGException("Response body for a sticker is null :/"), downloadedStickers, call, fileDownloadRequest, this);
|
||||
return;
|
||||
}
|
||||
|
||||
InputStream stickerInputStream = responseBody.a();
|
||||
Bitmap stickerImage = BitmapFactory.decodeStream(stickerInputStream);
|
||||
|
||||
if (stickerImage == null) {
|
||||
handleFailure(deathFlag, listener, new TSGException("Unable to decode sticker image"), downloadedStickers, call, fileDownloadRequest, this);
|
||||
return;
|
||||
}
|
||||
|
||||
File stickerFile = new File(packFolder, String.format(STICKER_FILE_NAME_FORMAT, stickerIndex));
|
||||
|
||||
try {
|
||||
saveStickerImage(stickerImage, stickerFile);
|
||||
} catch (TSGException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
listener.onStickerDownloaded(set.name, stickerFile, sticker.emoji, stickerIndex,
|
||||
downloadedStickers.value() + 1, set.stickers.size());
|
||||
downloadedStickers.increase();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
handleFailure(deathFlag, listener, e, downloadedStickers, call, fileInfoRequest, this);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void handleFailure(Flag deathFlag, PackDownloadListener listener, Exception e, GoalCounter downloadedStickers, Call call, Request request, Callback callback) {
|
||||
if ((e instanceof IOException || e instanceof TSGException) && retryCount.get() > MAX_RETRIES) {
|
||||
Log.e(TAG, "Unable to download sticker: " + e.getMessage());
|
||||
downloadedStickers.increase();
|
||||
return;
|
||||
} else if (retryCount.get() < MAX_RETRIES) {
|
||||
retryRequest(call, request, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
if (deathFlag.up()) {
|
||||
return;
|
||||
}
|
||||
|
||||
deathFlag.raise();
|
||||
listener.onPackDownloadError(e);
|
||||
}
|
||||
|
||||
private void retryRequest(Call call, Request request, Callback callback) {
|
||||
retryCount.incrementAndGet();
|
||||
|
||||
if (retryCount.get() > MAX_RETRIES) {
|
||||
Log.e(TAG, "retryRequest: max retries");
|
||||
callback.a(call, new IOException());
|
||||
} else {
|
||||
Log.e(TAG, "retryRequest");
|
||||
sClient.a(request).a(callback);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveStickerImage(Bitmap image, File file) throws TSGException {
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
image.compress(Bitmap.CompressFormat.PNG, 100, fos);
|
||||
} catch (IOException e) {
|
||||
throw new TSGException("Unable to save sticker image");
|
||||
}
|
||||
}
|
||||
|
||||
private void getPackInfo(String packName, File packFolder, String installedVersion, PackDownloadListener listener) {
|
||||
String getStickerSetUrl = String.format(GET_STICKER_SET_URL, botApiKey, packName);
|
||||
Request packInfoRequest = new Request.a()
|
||||
.b(getStickerSetUrl)
|
||||
.a();
|
||||
sClient.a(packInfoRequest).a(new Callback() {
|
||||
@Override
|
||||
public void onFailure(NetCall call, IOException e) {
|
||||
public void a(Call call, IOException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
listener.onPackDownloadError(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(NetCall call, NetResponse response) {
|
||||
if (!response.isSuccessful()) {
|
||||
if (response.getData() != null)
|
||||
listener.onPackDownloadError(new TSGException(response.getDataString() + "\nURL: " + call.request().url()));
|
||||
else
|
||||
listener.onPackDownloadError(new TSGException("Unknown Exception, no response body"));
|
||||
public void a(Call call, Response response) throws IOException {
|
||||
Log.d(TAG, response.toString());
|
||||
|
||||
if (!response.h()) {
|
||||
String errorMessage = response.a() != null ? response.a().g() + "\nURL: " + call.m0().g() : "Unknown Exception, no response body";
|
||||
listener.onPackDownloadError(new TSGException(errorMessage));
|
||||
return;
|
||||
}
|
||||
|
||||
StickerSet set;
|
||||
try {
|
||||
JSONObject jPackInfo = new JSONObject(response.getDataString()).getJSONObject("result");
|
||||
String packVersion = new String(sha256.digest(jPackInfo.toString().getBytes(StandardCharsets.UTF_8)));
|
||||
try (ResponseBody responseBody = response.a()) {
|
||||
JSONObject packInfoResponse = new JSONObject(responseBody.g()).getJSONObject("result");
|
||||
String packVersion = new String(sha256.digest(packInfoResponse.toString().getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
if (packVersion.equals(installedVersion)) {
|
||||
listener.onPackDownloaded(null, false);
|
||||
return;
|
||||
}
|
||||
|
||||
JSONArray jStickers = jPackInfo.getJSONArray("stickers");
|
||||
JSONArray stickersArray = packInfoResponse.getJSONArray(STICKERS_KEY);
|
||||
|
||||
if (jStickers.length() == 0) {
|
||||
if (stickersArray.length() == 0) {
|
||||
listener.onPackDownloadError(new TSGException("No stickers in pack"));
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<Sticker> stickers = new ArrayList<>(jStickers.length());
|
||||
ArrayList<Sticker> stickers = parseStickers(stickersArray);
|
||||
|
||||
Log.d(TAG, String.format("Parsing stickers in pack %s", packName));
|
||||
StickerSet set = new StickerSet(packInfoResponse.getString(NAME_KEY), packInfoResponse.getString(TITLE_KEY), packVersion, stickers);
|
||||
|
||||
for (int i = 0; i < jStickers.length(); i++) {
|
||||
JSONObject jSticker = jStickers.getJSONObject(i);
|
||||
if (jSticker.optBoolean("is_animated") || jSticker.optBoolean("is_video")) {
|
||||
if (jSticker.has("thumb")) {
|
||||
stickers.add(new Sticker(jSticker.getJSONObject("thumb").getString("file_id"), jSticker.getString("emoji")));
|
||||
} else {
|
||||
listener.onPackDownloadError(new TSGException("Animated and video stickerpacks without thumbs are not supported!"));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
stickers.add(new Sticker(jSticker.getString("file_id"), jSticker.getString("emoji")));
|
||||
}
|
||||
if (!packFolder.exists() && !packFolder.mkdirs()) {
|
||||
// Handle the folder creation failure case
|
||||
listener.onPackDownloadError(new IOException("Can't create folder for the pack!"));
|
||||
return;
|
||||
}
|
||||
|
||||
set = new StickerSet(jPackInfo.getString("name"), jPackInfo.getString("title"), packVersion, stickers);
|
||||
Log.d(TAG, String.format("Got info for pack %s, now downloading stickers to %s", packName, packFolder.getAbsolutePath()));
|
||||
|
||||
TelegramStickersPackInfo packInfo = new TelegramStickersPackInfo(packName, set.name, set.stickers.size(), set.version);
|
||||
|
||||
listener.onGotPackInfo(packInfo);
|
||||
|
||||
getPack(set, packFolder, packInfo, listener);
|
||||
} catch (Exception e) {
|
||||
listener.onPackDownloadError(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!packFolder.exists() && !packFolder.mkdirs()) {
|
||||
listener.onPackDownloadError(new IOException("Can't create folder for the pack!"));
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, String.format("Got info for pack %s, now downloading stickers to %s", packName, packFolder.getAbsolutePath()));
|
||||
|
||||
TelegramStickersPackInfo packInfo = new TelegramStickersPackInfo(packName, set.name, set.stickers.size(), set.version);
|
||||
listener.onGotPackInfo(packInfo);
|
||||
getPack(set, packFolder, packInfo, listener);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void getPack(final StickerSet set, final File packFolder, final TelegramStickersPackInfo packInfo, final PackDownloadListener listener) {
|
||||
final GoalCounter downloadedStickers = new GoalCounter(set.stickers.size(), () -> {
|
||||
Log.d(TAG, String.format("Pack %s has been downloaded to %s", set.id, packFolder.getAbsolutePath()));
|
||||
private ArrayList<Sticker> parseStickers(JSONArray stickersArray) throws JSONException, TSGException {
|
||||
ArrayList<Sticker> stickers = new ArrayList<>(stickersArray.length());
|
||||
|
||||
listener.onPackDownloaded(packInfo, true);
|
||||
});
|
||||
final Flag deathFlag = new Flag();
|
||||
for (int i = 0; i < stickersArray.length(); i++) {
|
||||
JSONObject stickerObject = stickersArray.getJSONObject(i);
|
||||
boolean isAnimated = stickerObject.optBoolean(IS_ANIMATED_KEY);
|
||||
boolean isVideo = stickerObject.optBoolean(IS_VIDEO_KEY);
|
||||
String fileId = stickerObject.getString(FILE_ID_KEY);
|
||||
String emoji = stickerObject.getString(EMOJI_KEY);
|
||||
|
||||
AtomicInteger retryed = new AtomicInteger();
|
||||
for (int i = 0; i < set.stickers.size(); i++) {
|
||||
final Sticker sticker = set.stickers.get(i);
|
||||
NetRequest fileInfoRequest = new NetRequest.Builder().get().url(String.format(GET_FILE_URL, botApiKey, sticker.fileId)).build();
|
||||
|
||||
final int stickerIndex = i + 1;
|
||||
|
||||
AtomicBoolean sync = new AtomicBoolean();
|
||||
httpClient.newCall(fileInfoRequest).enqueue(new NetCallback() {
|
||||
@Override
|
||||
public void onFailure(NetCall call, IOException e) {
|
||||
if (deathFlag.up())
|
||||
return;
|
||||
|
||||
deathFlag.raise();
|
||||
listener.onPackDownloadError(e);
|
||||
|
||||
sync.set(true);
|
||||
if (isAnimated || isVideo) {
|
||||
if (stickerObject.has(THUMB_KEY)) {
|
||||
fileId = stickerObject.getJSONObject(THUMB_KEY).getString(FILE_ID_KEY);
|
||||
} else {
|
||||
throw new TSGException("Animated and video stickerpacks without thumbs are not supported!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(NetCall call, NetResponse response) throws IOException {
|
||||
if (deathFlag.up())
|
||||
return;
|
||||
|
||||
if (response.code() != 200) {
|
||||
retryed.incrementAndGet();
|
||||
|
||||
if (retryed.get() > 5)
|
||||
onFailure(call, new IOException());
|
||||
else httpClient.newCall(fileInfoRequest)
|
||||
.enqueue(this);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
String filePath;
|
||||
try {
|
||||
JSONObject jFileInfo = new JSONObject(response.getDataString()).getJSONObject("result");
|
||||
filePath = jFileInfo.getString("file_path");
|
||||
} catch (Exception e) {
|
||||
deathFlag.raise();
|
||||
listener.onPackDownloadError(e);
|
||||
sync.set(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (botApiKey == null) botApiKey = "";
|
||||
|
||||
NetRequest fileDownloadRequest = new NetRequest.Builder().get().url(String.format(BOT_API_BASE_FILE_URL, botApiKey, filePath)).build();
|
||||
|
||||
httpClient.newCall(fileDownloadRequest).enqueue(new NetCallback() {
|
||||
@Override
|
||||
public void onFailure(NetCall call, IOException e) {
|
||||
if (deathFlag.up())
|
||||
return;
|
||||
|
||||
deathFlag.raise();
|
||||
listener.onPackDownloadError(e);
|
||||
|
||||
sync.set(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(NetCall call, NetResponse response) throws IOException {
|
||||
if (deathFlag.up())
|
||||
return;
|
||||
|
||||
if (response.code() != 200) {
|
||||
retryed.incrementAndGet();
|
||||
|
||||
if (retryed.get() > 5)
|
||||
onFailure(call, new IOException());
|
||||
else httpClient.newCall(fileDownloadRequest)
|
||||
.enqueue(this);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.getData() == null) {
|
||||
deathFlag.raise();
|
||||
listener.onPackDownloadError(new TSGException("Response body for a sticker is null :/"));
|
||||
sync.set(true);
|
||||
return;
|
||||
}
|
||||
|
||||
InputStream stickerInputStream = response.getDataStream();
|
||||
|
||||
Bitmap stickerImage = BitmapFactory.decodeStream(stickerInputStream);
|
||||
|
||||
try {
|
||||
stickerInputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
deathFlag.raise();
|
||||
listener.onPackDownloadError(e);
|
||||
sync.set(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (stickerImage == null) {
|
||||
deathFlag.raise();
|
||||
listener.onPackDownloadError(new TSGException("Unable to decode sticker image"));
|
||||
sync.set(true);
|
||||
return;
|
||||
}
|
||||
|
||||
File stickerFile = new File(packFolder, String.format("%03d.png", stickerIndex));
|
||||
|
||||
FileOutputStream fileOutputStream;
|
||||
try {
|
||||
fileOutputStream = new FileOutputStream(stickerFile);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
deathFlag.raise();
|
||||
listener.onPackDownloadError(e);
|
||||
sync.set(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!stickerImage.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)) {
|
||||
stickerImage.recycle();
|
||||
deathFlag.raise();
|
||||
listener.onPackDownloadError(new TSGException("Unable to compress sticker to a png file at path: " + stickerFile.getAbsolutePath()));
|
||||
sync.set(true);
|
||||
return;
|
||||
}
|
||||
|
||||
stickerImage.recycle();
|
||||
|
||||
try {
|
||||
fileOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
deathFlag.raise();
|
||||
listener.onPackDownloadError(e);
|
||||
sync.set(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
listener.onStickerDownloaded(set.name, stickerFile, sticker.emoji, stickerIndex, downloadedStickers.value() + 1, set.stickers.size());
|
||||
downloadedStickers.increase();
|
||||
|
||||
sync.set(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
while (!sync.get())
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e1) {
|
||||
}
|
||||
stickers.add(new Sticker(fileId, emoji));
|
||||
}
|
||||
|
||||
return stickers;
|
||||
}
|
||||
|
||||
private void runOnUiThread(Runnable r) {
|
||||
@@ -431,15 +345,13 @@ public class TelegramStickersGrabber {
|
||||
void onNetError();
|
||||
}
|
||||
|
||||
public class TSGException extends Exception {
|
||||
private static final long serialVersionUID = 7866915509988422944L;
|
||||
|
||||
public static class TSGException extends Exception {
|
||||
private TSGException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
private class StickerSet {
|
||||
private static class StickerSet {
|
||||
String id;
|
||||
String name;
|
||||
String version;
|
||||
@@ -453,7 +365,7 @@ public class TelegramStickersGrabber {
|
||||
}
|
||||
}
|
||||
|
||||
private class Sticker {
|
||||
private static class Sticker {
|
||||
String emoji;
|
||||
String fileId;
|
||||
|
||||
|
||||
@@ -1,342 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,232 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
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);
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
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() {
|
||||
}
|
||||
}
|
||||
@@ -1,253 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
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,13 +1,10 @@
|
||||
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;
|
||||
@@ -15,9 +12,6 @@ import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -2140,8 +2140,6 @@ 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 {
|
||||
@@ -2162,9 +2160,6 @@ 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 {
|
||||
@@ -2973,13 +2968,6 @@ 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
|
||||
}
|
||||
@@ -3833,21 +3821,6 @@ 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
|
||||
@@ -5026,9 +4999,6 @@ public final class R {
|
||||
public static final int custom_thumb_selector = 0x7f080be9; // 2131233769
|
||||
public static final int custom_track_selector = 0x7f080bea; // 2131233770
|
||||
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
|
||||
@@ -11092,12 +11062,6 @@ 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 {
|
||||
@@ -11144,10 +11108,6 @@ 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
|
||||
@@ -12923,11 +12883,6 @@ 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 {
|
||||
@@ -19703,43 +19658,12 @@ public final class R {
|
||||
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 int cache_size = 0x7f12188d; // 2131892365
|
||||
public static final int cache_size_summ = 0x7f12188e; // 2131892366
|
||||
public static final int clear_all_cache = 0x7f12188f; // 2131892367
|
||||
public static final int invalidate_theme_cache_each_update_title = 0x7f121890; // 2131892368
|
||||
public static final int invertFilters = 0x7f121891; // 2131892369
|
||||
public static final int invertFilters_summ = 0x7f121892; // 2131892370
|
||||
}
|
||||
|
||||
public static final class style {
|
||||
@@ -20875,11 +20799,6 @@ 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
|
||||
|
||||
@@ -0,0 +1,505 @@
|
||||
package com.vtosters.lite.api.execute;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.RectF;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import com.vk.api.base.utils.ApiUtils;
|
||||
import com.vk.core.network.Network;
|
||||
import com.vk.core.util.AppContextHolder;
|
||||
import com.vk.core.util.Screen;
|
||||
import com.vk.dto.common.data.VKList;
|
||||
import com.vk.dto.gift.GiftItem;
|
||||
import com.vk.dto.group.Group;
|
||||
import com.vk.dto.newsfeed.entries.ProfilesRecommendations;
|
||||
import com.vk.dto.photo.Photo;
|
||||
import com.vk.dto.user.UserProfile;
|
||||
import com.vk.dto.user.deactivation.UserDeactivation;
|
||||
import com.vtosters.lite.api.ExtendedUserProfile;
|
||||
import com.vtosters.lite.auth.VKAccountManager;
|
||||
import com.vtosters.lite.utils.Utils;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.OnlineFormatterHook;
|
||||
import ru.vtosters.hooks.RenameHook;
|
||||
import ru.vtosters.hooks.ssfs.ProfileHook;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.lite.proxy.ProxyUtils;
|
||||
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GetFullUserProfile extends GetFullProfile<ExtendedUserProfile> {
|
||||
private static final OkHttpClient mClient = VtOkHttpClient.getInstance();
|
||||
|
||||
public GetFullUserProfile(int i, String str, String str2) {
|
||||
super(i, "execute.getFullProfileNewNew");
|
||||
i = i == 0 ? VKAccountManager.d().D0() : i;
|
||||
b("user_id", i);
|
||||
b("func_v", 23); // 11
|
||||
this.F = i;
|
||||
if (!TextUtils.isEmpty(str2)) {
|
||||
c("source", str2);
|
||||
}
|
||||
b("photo_sizes", 1);
|
||||
b("skip_hidden", 1);
|
||||
if (TextUtils.isEmpty(str)) {
|
||||
return;
|
||||
}
|
||||
c("access_keys", str);
|
||||
}
|
||||
|
||||
public JSONArray getCitiesNames(String ids) {
|
||||
var request = new Request.a()
|
||||
.b("https://" + ProxyUtils.getApi() + "/method/" + "database.getCitiesById"
|
||||
+ "?v=5.119"
|
||||
+ "&city_ids="
|
||||
+ ids
|
||||
+ "&access_token="
|
||||
+ AccountManagerUtils.getUserToken())
|
||||
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8")).a();
|
||||
|
||||
try {
|
||||
return new JSONObject(mClient.a(request).execute().a().g()).getJSONArray("response");
|
||||
} catch (JSONException | IOException e) {
|
||||
Log.d(this.getClass().getSimpleName(), e.toString());
|
||||
}
|
||||
|
||||
return new JSONArray();
|
||||
}
|
||||
|
||||
public JSONArray getCountriesNames(String ids) {
|
||||
var request = new Request.a()
|
||||
.b("https://" + ProxyUtils.getApi() + "/method/" + "database.getCountriesById"
|
||||
+ "?v=5.119"
|
||||
+ "&country_ids="
|
||||
+ ids
|
||||
+ "&access_token="
|
||||
+ AccountManagerUtils.getUserToken())
|
||||
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8")).a();
|
||||
|
||||
try {
|
||||
return new JSONObject(mClient.a(request).execute().a().g()).getJSONArray("response");
|
||||
} catch (JSONException | IOException e) {
|
||||
Log.d(this.getClass().getSimpleName(), e.toString());
|
||||
}
|
||||
|
||||
return new JSONArray();
|
||||
}
|
||||
|
||||
|
||||
protected ExtendedUserProfile o() {
|
||||
return new ExtendedUserProfile();
|
||||
}
|
||||
|
||||
@SuppressLint("ResourceType")
|
||||
public void a(ExtendedUserProfile extendedUserProfile, JSONObject jSONObject) throws JSONException {
|
||||
char c;
|
||||
RenameHook.injectIntoJson(jSONObject);
|
||||
JSONObject onlineHook = OnlineFormatterHook.onlineHook(jSONObject);
|
||||
UserProfile userProfile = extendedUserProfile.a;
|
||||
int i = onlineHook.getInt("id");
|
||||
this.F = i;
|
||||
userProfile.b = i;
|
||||
ProfileHook.fetchInfo(extendedUserProfile, onlineHook);
|
||||
|
||||
extendedUserProfile.a.c = onlineHook.getString("first_name");
|
||||
extendedUserProfile.a.e = onlineHook.getString("last_name");
|
||||
extendedUserProfile.a.d = extendedUserProfile.a.c + " " + extendedUserProfile.a.e;
|
||||
extendedUserProfile.a.f = onlineHook.getString(Screen.a() > 1.0f ? "photo_medium_rec" : "photo_rec");
|
||||
extendedUserProfile.a.h = onlineHook.getInt("friend_status") == 3;
|
||||
extendedUserProfile.j = onlineHook.optString("photo_max", onlineHook.getString("photo_medium_rec"));
|
||||
extendedUserProfile.m = onlineHook.optString("activity", "");
|
||||
extendedUserProfile.a.g = onlineHook.getInt("sex") == 1;
|
||||
extendedUserProfile.a.E = UserProfile.d(jSONObject);
|
||||
|
||||
if (onlineHook.has("crop_photo")) {
|
||||
extendedUserProfile.k = new Photo(onlineHook.getJSONObject("crop_photo").getJSONObject("photo"));
|
||||
JSONObject jSONObject2 = onlineHook.getJSONObject("crop_photo").getJSONObject("rect");
|
||||
JSONObject jSONObject3 = onlineHook.getJSONObject("crop_photo").getJSONObject("crop");
|
||||
double d = jSONObject3.getDouble("x");
|
||||
double d2 = jSONObject3.getDouble("x2");
|
||||
double d3 = jSONObject3.getDouble("y");
|
||||
double d4 = jSONObject3.getDouble("y2");
|
||||
double d5 = jSONObject2.getDouble("x");
|
||||
double d6 = jSONObject2.getDouble("x2");
|
||||
double d7 = jSONObject2.getDouble("y");
|
||||
double d8 = (d2 - d) / 100.0d;
|
||||
double d9 = (d4 - d3) / 100.0d;
|
||||
double d10 = (d / 100.0d) + ((d5 / 100.0d) * d8);
|
||||
double d11 = (d3 / 100.0d) + ((d7 / 100.0d) * d9);
|
||||
extendedUserProfile.l = new RectF((float) d10, (float) d11, (float) (d10 + (((d6 - d5) / 100.0d) * d8)), (float) (d11 + (((jSONObject2.getDouble("y2") - d7) / 100.0d) * d9)));
|
||||
}
|
||||
|
||||
SparseArray<String> sparseArray = new SparseArray<>();
|
||||
SparseArray<String> sparseArray2 = new SparseArray<>();
|
||||
|
||||
if (onlineHook.has("cities") && onlineHook.getJSONArray("cities").length() > 0) {
|
||||
List<String> cityNames = new ArrayList<>();
|
||||
|
||||
JSONArray cities = onlineHook.getJSONArray("cities");
|
||||
|
||||
for (int i21 = 0; i21 < cities.length(); i21++) {
|
||||
cityNames.add(cities.getString(i21));
|
||||
}
|
||||
|
||||
JSONArray citiesNamesJSONArray = getCitiesNames(String.join(", ", cityNames));
|
||||
|
||||
Log.d(this.getClass().getSimpleName(), citiesNamesJSONArray.toString());
|
||||
|
||||
for (int i22 = 0; i22 < citiesNamesJSONArray.length(); i22++) {
|
||||
JSONObject cityJSONObject = citiesNamesJSONArray.getJSONObject(i22);
|
||||
int cityid = cityJSONObject.getInt("id");
|
||||
String cityTitle = cityJSONObject.getString("title");
|
||||
sparseArray.put(cityid, cityTitle);
|
||||
}
|
||||
|
||||
extendedUserProfile.i0 = sparseArray.get(cities.getInt(0));
|
||||
}
|
||||
|
||||
if (onlineHook.has("countries") && onlineHook.getJSONArray("countries").length() > 0) {
|
||||
JSONArray countries = onlineHook.getJSONArray("countries");
|
||||
List<String> countryList = new ArrayList<>();
|
||||
|
||||
for (int i23 = 0; i23 < countries.length(); i23++) {
|
||||
countryList.add(countries.getString(i23));
|
||||
}
|
||||
|
||||
JSONArray countryInfo = getCountriesNames(String.join(", ", countryList));
|
||||
|
||||
Log.d(this.getClass().getSimpleName(), countryInfo.toString());
|
||||
|
||||
for (int i24 = 0; i24 < countryInfo.length(); i24++) {
|
||||
JSONObject country = countryInfo.getJSONObject(i24);
|
||||
int countryid = country.getInt("id");
|
||||
String countryTitle = country.getString("title");
|
||||
sparseArray2.put(countryid, countryTitle);
|
||||
}
|
||||
|
||||
extendedUserProfile.j0 = sparseArray2.get(countries.getInt(0));
|
||||
}
|
||||
|
||||
extendedUserProfile.U = onlineHook.getInt("can_write_private_message") == 1;
|
||||
extendedUserProfile.X = onlineHook.getInt("can_post") == 1;
|
||||
extendedUserProfile.Y = onlineHook.optInt("can_suggest") == 1;
|
||||
extendedUserProfile.V = onlineHook.optInt("can_see_all_posts") == 1;
|
||||
extendedUserProfile.f0 = onlineHook.optInt("can_see_archived_posts") == 1;
|
||||
extendedUserProfile.a0 = "all".equals(onlineHook.optString("wall_default"));
|
||||
extendedUserProfile.W = onlineHook.optBoolean("can_call", false);
|
||||
extendedUserProfile.Z = onlineHook.optInt("blacklisted_by_me") == 1;
|
||||
|
||||
if (onlineHook.optInt("blacklisted") == 1) {
|
||||
extendedUserProfile.Y0 = new ExtendedUserProfile.c();
|
||||
}
|
||||
|
||||
extendedUserProfile.u = onlineHook.optInt("relation");
|
||||
if (onlineHook.has("relation_partner")) {
|
||||
extendedUserProfile.v = onlineHook.getJSONObject("relation_partner").getInt("id");
|
||||
extendedUserProfile.w = onlineHook.getJSONObject("relation_partner").getString("first_name") + " " + onlineHook.getJSONObject("relation_partner").getString("last_name");
|
||||
}
|
||||
|
||||
if (onlineHook.has("bdate")) {
|
||||
String string = onlineHook.getString("bdate");
|
||||
extendedUserProfile.a.I = string;
|
||||
String[] split = string.split("\\.");
|
||||
extendedUserProfile.s = Integer.parseInt(split[0]);
|
||||
extendedUserProfile.t = Integer.parseInt(split[1]);
|
||||
if (split.length > 2) {
|
||||
extendedUserProfile.r = Integer.parseInt(split[2]);
|
||||
}
|
||||
}
|
||||
|
||||
extendedUserProfile.d = onlineHook.optString("first_name_dat", extendedUserProfile.a.c);
|
||||
extendedUserProfile.b = onlineHook.optString("first_name_gen", extendedUserProfile.a.c);
|
||||
extendedUserProfile.c = onlineHook.optString("first_name_ins", extendedUserProfile.a.c);
|
||||
extendedUserProfile.h = onlineHook.optString("first_name_acc", extendedUserProfile.a.c);
|
||||
extendedUserProfile.g = onlineHook.optString("last_name_dat", extendedUserProfile.a.e);
|
||||
extendedUserProfile.e = onlineHook.optString("last_name_gen", extendedUserProfile.a.e);
|
||||
extendedUserProfile.f = onlineHook.optString("last_name_ins", extendedUserProfile.a.e);
|
||||
|
||||
String optString = onlineHook.optString("last_name_acc", extendedUserProfile.a.e);
|
||||
extendedUserProfile.i = optString;
|
||||
|
||||
if (onlineHook.has("mobile_phone") && !onlineHook.getString("mobile_phone").isEmpty()) {
|
||||
extendedUserProfile.l0 = onlineHook.getString("mobile_phone");
|
||||
}
|
||||
|
||||
if (onlineHook.has("home_phone") && !onlineHook.getString("home_phone").isEmpty()) {
|
||||
extendedUserProfile.m0 = onlineHook.getString("home_phone");
|
||||
}
|
||||
|
||||
if (onlineHook.has("skype")) {
|
||||
extendedUserProfile.n0 = onlineHook.getString("skype");
|
||||
}
|
||||
|
||||
if (onlineHook.has("twitter")) {
|
||||
extendedUserProfile.o0 = onlineHook.getString("twitter");
|
||||
}
|
||||
|
||||
if (onlineHook.has("livejournal")) {
|
||||
extendedUserProfile.r0 = onlineHook.getString("livejournal");
|
||||
}
|
||||
|
||||
if (onlineHook.has("facebook") && onlineHook.optLong("facebook", -1L) != -1) {
|
||||
extendedUserProfile.q0 = onlineHook.getLong("facebook");
|
||||
extendedUserProfile.p0 = onlineHook.getString("facebook_name");
|
||||
}
|
||||
|
||||
if (onlineHook.has("instagram")) {
|
||||
extendedUserProfile.u0 = onlineHook.getString("instagram");
|
||||
}
|
||||
|
||||
extendedUserProfile.R0 = onlineHook.getInt("friend_status");
|
||||
JSONArray optJSONArray = onlineHook.optJSONArray("schools");
|
||||
extendedUserProfile.v0 = new ArrayList<>();
|
||||
|
||||
ArrayList arrayList = null;
|
||||
if (optJSONArray != null) {
|
||||
for (int i4 = 0; i4 < optJSONArray.length(); i4++) {
|
||||
ExtendedUserProfile.f fVar = new ExtendedUserProfile.f();
|
||||
JSONObject jSONObject6 = optJSONArray.getJSONObject(i4);
|
||||
fVar.c = sparseArray.get(jSONObject6.optInt(optString));
|
||||
fVar.a = jSONObject6.optString("name", "???");
|
||||
fVar.g = jSONObject6.optInt("year_from");
|
||||
fVar.f = jSONObject6.optInt("year_to");
|
||||
fVar.h = jSONObject6.optInt("year_graduated");
|
||||
fVar.b = jSONObject6.optString("class", null);
|
||||
fVar.d = jSONObject6.optString("speciality", null);
|
||||
fVar.e = jSONObject6.optString("type_str", AppContextHolder.a.getResources().getString(2131889117));
|
||||
extendedUserProfile.v0.add(fVar);
|
||||
}
|
||||
}
|
||||
extendedUserProfile.w0 = new ArrayList<>();
|
||||
|
||||
JSONArray optJSONArray2 = onlineHook.optJSONArray("universities");
|
||||
if (optJSONArray2 != null) {
|
||||
for (int i5 = 0; i5 < optJSONArray2.length(); i5++) {
|
||||
ExtendedUserProfile.g gVar = new ExtendedUserProfile.g();
|
||||
JSONObject jSONObject7 = optJSONArray2.getJSONObject(i5);
|
||||
gVar.a = jSONObject7.getString("name").trim();
|
||||
if (jSONObject7.has("faculty_name")) {
|
||||
gVar.b = jSONObject7.getString("faculty_name").trim();
|
||||
}
|
||||
if (jSONObject7.has("chair_name")) {
|
||||
gVar.c = jSONObject7.getString("chair_name").trim();
|
||||
}
|
||||
gVar.d = jSONObject7.optInt("graduation");
|
||||
extendedUserProfile.w0.add(gVar);
|
||||
}
|
||||
}
|
||||
|
||||
if (onlineHook.has("interests") && onlineHook.getString("interests").length() > 0) {
|
||||
extendedUserProfile.y0 = onlineHook.getString("interests");
|
||||
}
|
||||
|
||||
if (onlineHook.has("movies") && onlineHook.getString("movies").length() > 0) {
|
||||
extendedUserProfile.A0 = onlineHook.getString("movies");
|
||||
}
|
||||
|
||||
if (onlineHook.has("music") && onlineHook.getString("music").length() > 0) {
|
||||
extendedUserProfile.z0 = onlineHook.getString("music");
|
||||
}
|
||||
|
||||
if (onlineHook.has("tv") && onlineHook.getString("tv").length() > 0) {
|
||||
extendedUserProfile.B0 = onlineHook.getString("tv");
|
||||
}
|
||||
|
||||
if (onlineHook.has("books") && onlineHook.getString("books").length() > 0) {
|
||||
extendedUserProfile.C0 = onlineHook.getString("books");
|
||||
}
|
||||
|
||||
if (onlineHook.has("games") && onlineHook.getString("games").length() > 0) {
|
||||
extendedUserProfile.D0 = onlineHook.getString("games");
|
||||
}
|
||||
|
||||
if (onlineHook.has("about") && onlineHook.getString("about").length() > 0) {
|
||||
extendedUserProfile.F0 = onlineHook.getString("about");
|
||||
}
|
||||
|
||||
if (onlineHook.has("quotes") && onlineHook.getString("quotes").length() > 0) {
|
||||
extendedUserProfile.E0 = onlineHook.getString("quotes");
|
||||
}
|
||||
|
||||
if (onlineHook.has("activities") && onlineHook.getString("activities").length() > 0) {
|
||||
extendedUserProfile.x0 = onlineHook.getString("activities");
|
||||
}
|
||||
|
||||
if (onlineHook.has("home_town") && onlineHook.getString("home_town").length() > 0) {
|
||||
extendedUserProfile.g0 = onlineHook.getString("home_town");
|
||||
}
|
||||
|
||||
if (onlineHook.has("site") && onlineHook.getString("site").length() > 0) {
|
||||
extendedUserProfile.M = onlineHook.getString("site");
|
||||
}
|
||||
|
||||
extendedUserProfile.a.Q.b(onlineHook);
|
||||
|
||||
JSONObject optJSONObject = onlineHook.optJSONObject("personal");
|
||||
if (optJSONObject != null) {
|
||||
JSONArray optJSONArray3 = optJSONObject.optJSONArray("langs");
|
||||
|
||||
if (optJSONArray3 != null) {
|
||||
ArrayList arrayList2 = new ArrayList<>();
|
||||
for (int i6 = 0; i6 < optJSONArray3.length(); i6++) {
|
||||
arrayList2.add(optJSONArray3.getString(i6));
|
||||
}
|
||||
extendedUserProfile.G0 = TextUtils.join(", ", arrayList2);
|
||||
}
|
||||
|
||||
extendedUserProfile.J0 = optJSONObject.optInt("political");
|
||||
extendedUserProfile.H0 = optJSONObject.optString("religion");
|
||||
extendedUserProfile.K0 = optJSONObject.optInt("life_main");
|
||||
extendedUserProfile.L0 = optJSONObject.optInt("people_main");
|
||||
extendedUserProfile.I0 = optJSONObject.optString("inspired_by");
|
||||
extendedUserProfile.M0 = optJSONObject.optInt("smoking");
|
||||
extendedUserProfile.N0 = optJSONObject.optInt("alcohol");
|
||||
}
|
||||
|
||||
SparseArray sparseArray3 = new SparseArray();
|
||||
JSONArray optJSONArray4 = onlineHook.optJSONArray("relatives_profiles");
|
||||
if (optJSONArray4 != null) {
|
||||
for (int i7 = 0; i7 < optJSONArray4.length(); i7++) {
|
||||
UserProfile userProfile2 = new UserProfile(optJSONArray4.getJSONObject(i7));
|
||||
sparseArray3.put(userProfile2.b, userProfile2);
|
||||
}
|
||||
}
|
||||
|
||||
JSONArray optJSONArray5 = onlineHook.optJSONArray("relatives");
|
||||
if (optJSONArray5 != null) {
|
||||
ArrayList arrayList3 = null;
|
||||
ArrayList arrayList4 = null;
|
||||
ArrayList arrayList5 = null;
|
||||
ArrayList arrayList6 = null;
|
||||
for (int i8 = 0; i8 < optJSONArray5.length(); i8++) {
|
||||
JSONObject jSONObject8 = optJSONArray5.getJSONObject(i8);
|
||||
int i9 = jSONObject8.getInt("id");
|
||||
if (ApiUtils.a(sparseArray3, i9)) {
|
||||
String valueOf = jSONObject8.getString("type");
|
||||
switch (valueOf.hashCode()) {
|
||||
case -995424086 -> {
|
||||
if (valueOf.equals("parent")) {
|
||||
c = 4;
|
||||
break;
|
||||
}
|
||||
c = 65535;
|
||||
}
|
||||
case -268316490 -> {
|
||||
if (valueOf.equals("grandparent")) {
|
||||
c = 1;
|
||||
break;
|
||||
}
|
||||
c = 65535;
|
||||
}
|
||||
case 94631196 -> {
|
||||
if (valueOf.equals("child")) {
|
||||
c = 2;
|
||||
break;
|
||||
}
|
||||
c = 65535;
|
||||
}
|
||||
case 395180944 -> {
|
||||
if (valueOf.equals("grandchild")) {
|
||||
c = 0;
|
||||
break;
|
||||
}
|
||||
c = 65535;
|
||||
}
|
||||
case 2083595970 -> {
|
||||
if (valueOf.equals("sibling")) {
|
||||
c = 3;
|
||||
break;
|
||||
}
|
||||
c = 65535;
|
||||
}
|
||||
default -> c = 65535;
|
||||
}
|
||||
switch (c) {
|
||||
case 0 -> arrayList6 = Utils.a(arrayList6, sparseArray3.get(i9));
|
||||
case 1 -> arrayList5 = Utils.a(arrayList5, sparseArray3.get(i9));
|
||||
case 2 -> arrayList4 = Utils.a(arrayList4, sparseArray3.get(i9));
|
||||
case 3 -> arrayList3 = Utils.a(arrayList3, sparseArray3.get(i9));
|
||||
case 4 -> arrayList = Utils.a(arrayList, sparseArray3.get(i9));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extendedUserProfile.A = Utils.a((ArrayList<UserProfile>) arrayList, UserProfile.CREATOR);
|
||||
extendedUserProfile.B = Utils.a((ArrayList<UserProfile>) arrayList3, UserProfile.CREATOR);
|
||||
extendedUserProfile.C = Utils.a((ArrayList<UserProfile>) arrayList4, UserProfile.CREATOR);
|
||||
extendedUserProfile.D = Utils.a((ArrayList<UserProfile>) arrayList5, UserProfile.CREATOR);
|
||||
extendedUserProfile.E = Utils.a((ArrayList<UserProfile>) arrayList6, UserProfile.CREATOR);
|
||||
}
|
||||
|
||||
JSONObject optJSONObject2 = onlineHook.optJSONObject("owner_state");
|
||||
if (optJSONObject2 != null) {
|
||||
extendedUserProfile.q = UserDeactivation.CREATOR.a(optJSONObject2);
|
||||
}
|
||||
|
||||
JSONObject optJSONObject3 = onlineHook.optJSONObject("gifts");
|
||||
if (optJSONObject3 != null) {
|
||||
extendedUserProfile.y1 = new VKList<>(optJSONObject3, GiftItem.C);
|
||||
}
|
||||
|
||||
JSONArray optJSONArray6 = onlineHook.optJSONArray("friends");
|
||||
if (optJSONArray6 != null) {
|
||||
extendedUserProfile.H = new ArrayList<>();
|
||||
for (int i10 = 0; i10 < optJSONArray6.length(); i10++) {
|
||||
extendedUserProfile.H.add(new UserProfile(optJSONArray6.getJSONObject(i10)));
|
||||
}
|
||||
}
|
||||
|
||||
if (onlineHook.has("career")) {
|
||||
extendedUserProfile.I = new ArrayList<>();
|
||||
JSONArray jSONArray3 = onlineHook.getJSONArray("career");
|
||||
for (int i11 = 0; i11 < jSONArray3.length(); i11++) {
|
||||
JSONObject jSONObject9 = jSONArray3.getJSONObject(i11);
|
||||
ExtendedUserProfile.e eVar = new ExtendedUserProfile.e();
|
||||
if (jSONObject9.has("group")) {
|
||||
eVar.a = new Group(jSONObject9.getJSONObject("group"));
|
||||
} else {
|
||||
eVar.c = jSONObject9.getString("company");
|
||||
}
|
||||
eVar.e = jSONObject9.optInt("from");
|
||||
eVar.f = jSONObject9.optInt("until");
|
||||
eVar.d = jSONObject9.optString("position");
|
||||
extendedUserProfile.I.add(eVar);
|
||||
}
|
||||
}
|
||||
|
||||
if (onlineHook.has("display_fields")) {
|
||||
JSONArray jSONArray4 = onlineHook.getJSONArray("display_fields");
|
||||
extendedUserProfile.j1 = new ArrayList<>();
|
||||
for (int i12 = 0; i12 < jSONArray4.length(); i12++) {
|
||||
extendedUserProfile.j1.add(jSONArray4.getString(i12));
|
||||
}
|
||||
}
|
||||
|
||||
extendedUserProfile.u1 = onlineHook.getBoolean("all_photos_are_hidden");
|
||||
JSONObject optJSONObject4 = onlineHook.optJSONObject("friends_recommendations");
|
||||
if (optJSONObject4 != null) {
|
||||
extendedUserProfile.J = getFriendsRecomms(optJSONObject4);
|
||||
}
|
||||
}
|
||||
|
||||
public ProfilesRecommendations getFriendsRecomms(JSONObject json) {
|
||||
try {
|
||||
Method method = ProfilesRecommendations.class.getDeclaredMethod("b", JSONObject.class);
|
||||
return (ProfilesRecommendations) method.invoke(null, json);
|
||||
} catch (Exception e) {
|
||||
Log.d(this.getClass().getSimpleName(), e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public GetFullProfile.a a(JSONObject jSONObject) {
|
||||
return super.a(jSONObject);
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,6 @@ 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;
|
||||
@@ -25,14 +23,12 @@ 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;
|
||||
|
||||
public class MainActivityInjector {
|
||||
public static void inject(Activity activity) {
|
||||
SystemThemeChangerHook.themeOnStart(activity);
|
||||
sendRequest();
|
||||
UsersList.getUsersList();
|
||||
VTVerifications.load(activity);
|
||||
|
||||
@@ -69,13 +65,6 @@ public class MainActivityInjector {
|
||||
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) {
|
||||
final VKProgressDialog dialog = new VKProgressDialog(activity);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.vtosters.lite.R;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -115,14 +116,20 @@ public class OnlineFormatterHook {
|
||||
return AndroidUtils.getString(R.string.custom_online) + " " + appname;
|
||||
}
|
||||
|
||||
public static JSONObject onlineHook(JSONObject json) throws ParseException, IOException, JSONException {
|
||||
if (getBoolValue("onlinefix", false)) JsonInjectors.setOnlineInfo(json);
|
||||
public static JSONObject onlineHook(JSONObject json) {
|
||||
if (!getBoolValue("onlinefix", false) || Preferences.serverFeaturesDisable()) return json;
|
||||
|
||||
try {
|
||||
JsonInjectors.setOnlineInfo(json);
|
||||
} catch (JSONException e) {
|
||||
Log.e("onlineHook", e.getMessage());
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public static JSONArray onlineHookList(JSONArray jsonArr) throws ParseException, IOException, JSONException {
|
||||
if (!getBoolValue("onlinefix", false)) return jsonArr;
|
||||
public static JSONArray onlineHookList(JSONArray jsonArr) {
|
||||
if (!getBoolValue("onlinefix", false) || Preferences.serverFeaturesDisable()) return jsonArr;
|
||||
|
||||
try {
|
||||
JsonInjectors.setOnlineInfoUsers(jsonArr);
|
||||
@@ -134,7 +141,7 @@ public class OnlineFormatterHook {
|
||||
}
|
||||
|
||||
public static JSONObject onlineHookProfiles(JSONObject json) {
|
||||
if (!getBoolValue("onlinefix", false)) return json;
|
||||
if (!getBoolValue("onlinefix", false) || Preferences.serverFeaturesDisable()) return json;
|
||||
|
||||
try {
|
||||
JsonInjectors.setOnlineInfoUsers(json.optJSONArray("profiles"));
|
||||
@@ -146,7 +153,7 @@ public class OnlineFormatterHook {
|
||||
}
|
||||
|
||||
public static JSONObject onlineHookItems(JSONObject json) {
|
||||
if (!getBoolValue("onlinefix", false)) return json;
|
||||
if (!getBoolValue("onlinefix", false) || Preferences.serverFeaturesDisable()) return json;
|
||||
|
||||
try {
|
||||
JsonInjectors.setOnlineInfoUsers(json.optJSONArray("items"));
|
||||
@@ -157,8 +164,8 @@ public class OnlineFormatterHook {
|
||||
return json;
|
||||
}
|
||||
|
||||
public static JSONObject onlineHookRequestsAndRecommendations(JSONObject json) throws ParseException, IOException, JSONException {
|
||||
if (!getBoolValue("onlinefix", false)) return json;
|
||||
public static JSONObject onlineHookRequestsAndRecommendations(JSONObject json) {
|
||||
if (!getBoolValue("onlinefix", false) || Preferences.serverFeaturesDisable()) return json;
|
||||
|
||||
try {
|
||||
JsonInjectors.setOnlineInfoUsers(json.optJSONObject("read_requests").optJSONArray("items"));
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class TabletHook {
|
||||
public static boolean hook() {
|
||||
return AndroidUtils.isTablet() && !Preferences.getBoolValue("disableForceTabletMode", false);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package ru.vtosters.hooks;
|
||||
|
||||
import com.vk.dto.common.VerifyInfo;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.utils.VTVerifications;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
@@ -20,7 +21,7 @@ public class VerificationsHook {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!getBoolValue("VT_Verification", true)) {
|
||||
if (!getBoolValue("VT_Verification", true) || Preferences.serverFeaturesDisable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -32,7 +33,7 @@ public class VerificationsHook {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!getBoolValue("VT_Fire", true)) {
|
||||
if (!getBoolValue("VT_Fire", true) || Preferences.serverFeaturesDisable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -40,10 +41,6 @@ public class VerificationsHook {
|
||||
}
|
||||
|
||||
public static boolean hasDeveloper(JSONObject jSONObject) {
|
||||
if (!getBoolValue("VT_Dev", true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return VTVerifications.isDeveloper(VTVerifications.getId(jSONObject));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,10 @@ package ru.vtosters.hooks.other;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.StrictMode;
|
||||
import com.guardanis.applock.AppLock;
|
||||
import com.guardanis.applock.activities.UnlockActivity;
|
||||
import com.vk.medianative.MediaImageEncoder;
|
||||
import com.vk.medianative.MediaNative;
|
||||
import com.vtosters.lite.data.Users;
|
||||
@@ -36,15 +33,7 @@ public class Preferences {
|
||||
VTVerifications.load(application);
|
||||
LifecycleUtils.registerActivities(application);
|
||||
|
||||
if (AppLock.isEnrolled(AndroidUtils.getGlobalContext())) {
|
||||
AppLock.setAuthenticationRequired(AndroidUtils.getGlobalContext());
|
||||
}
|
||||
|
||||
AnalyticsHelper.start(application);
|
||||
|
||||
if (AppLock.isEnrolled(AndroidUtils.getGlobalContext())) {
|
||||
AppLock.setAuthenticationRequired(AndroidUtils.getGlobalContext());
|
||||
}
|
||||
} // VK Init
|
||||
|
||||
public static String getBuildName() {
|
||||
@@ -253,6 +242,10 @@ public class Preferences {
|
||||
return getBoolValue("autoalltranslate", false);
|
||||
}
|
||||
|
||||
public static boolean serverFeaturesDisable() {
|
||||
return getBoolValue("serverFeaturesDisable", false);
|
||||
}
|
||||
|
||||
public static boolean shortinfo() {
|
||||
return getBoolValue("shortinfo", true);
|
||||
}
|
||||
@@ -299,7 +292,7 @@ public class Preferences {
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public static boolean checkupdates() {
|
||||
return !getBoolValue("isRoamingState", false) && isValidSignature() && BuildConfig.BUILD_TYPE.equals("release");
|
||||
return !getBoolValue("isRoamingState", false) && isValidSignature() && BuildConfig.BUILD_TYPE.equals("release") && getBoolValue("autoupdates", true);
|
||||
}
|
||||
|
||||
public static boolean isNewBuild() {
|
||||
|
||||
@@ -24,7 +24,10 @@ public class ProfileHook {
|
||||
|
||||
if (UsersList.hasDescription(userID)) {
|
||||
try {
|
||||
extendedUserProfile.z2 = Handler.getDescription(userID);
|
||||
String description = Handler.getDescription(userID);
|
||||
if (!TextUtils.isEmpty(description)) {
|
||||
extendedUserProfile.z2 = description;
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
Log.e(TAG, "null \"profiles\" node\n" + e);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package ru.vtosters.lite.foaf;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vk.core.network.Network;
|
||||
import com.vtosters.lite.R;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@@ -15,13 +12,9 @@ import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.lite.net.Request;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -34,43 +27,15 @@ import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
|
||||
public class FoafBase {
|
||||
private static final Pattern FOAF_REGEX = Pattern.compile("<ya:created dc:date=\"(.+?)\"");
|
||||
private static final Pattern FOAF_REGEX_LAST_SEEN = Pattern.compile("<ya:lastLoggedIn dc:date=\"(.*)(((\\+|-)\\d\\d):(\\d\\d))\"");
|
||||
private static final String API_VKNEXT = "https://api.vtosters.app/v1/getBypassedOnlineInfo?json=1&ids=";
|
||||
private static final OkHttpClient client = VtOkHttpClient.getInstance();
|
||||
|
||||
public static long getLastSeen(long origtime, int id) throws ParseException {
|
||||
var request = new okhttp3.Request.a()
|
||||
.b(getLink(id))
|
||||
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8")).a();
|
||||
|
||||
String response = null;
|
||||
|
||||
try {
|
||||
response = client.a(request).execute().a().g();
|
||||
} catch (IOException e) {
|
||||
Log.e("FoafBase", e.getMessage());
|
||||
}
|
||||
|
||||
Matcher matcher = FOAF_REGEX_LAST_SEEN.matcher(response);
|
||||
|
||||
if (!matcher.find()) {
|
||||
return origtime;
|
||||
}
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
|
||||
sdf.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));
|
||||
Date date = sdf.parse(Objects.requireNonNull(matcher.group(1)));
|
||||
sdf.setTimeZone(TimeZone.getDefault());
|
||||
return sdf.parse(sdf.format(date)).getTime() / 1000;
|
||||
}
|
||||
|
||||
|
||||
public static JSONObject getBypassedOnlineInfo(int id) throws JSONException {
|
||||
var request = new okhttp3.Request.a()
|
||||
.b(API_VKNEXT + id)
|
||||
.a();
|
||||
|
||||
String response = null;
|
||||
String response;
|
||||
|
||||
var dummy = new JSONObject();
|
||||
dummy.put("last_seen", 0);
|
||||
@@ -86,7 +51,6 @@ public class FoafBase {
|
||||
}
|
||||
|
||||
public static JSONObject getBypassedOnlineInfo(String ids) {
|
||||
|
||||
var request = new okhttp3.Request.a()
|
||||
.b(API_VKNEXT + ids)
|
||||
.a();
|
||||
@@ -135,7 +99,15 @@ public class FoafBase {
|
||||
progressDialog.cancel();
|
||||
Matcher matcher = FOAF_REGEX.matcher(str);
|
||||
matcher.find();
|
||||
String normalHumanDate = getNormalHumanDate(Objects.requireNonNull(matcher.group(1)));
|
||||
|
||||
String m = matcher.group(1);
|
||||
|
||||
if (m == null) {
|
||||
LifecycleUtils.getCurrentActivity().runOnUiThread(() -> makeText(getGlobalContext(), context.getString(R.string.foaferr), LENGTH_SHORT).show());
|
||||
return;
|
||||
}
|
||||
|
||||
String normalHumanDate = getNormalHumanDate(m);
|
||||
|
||||
LifecycleUtils.getCurrentActivity().runOnUiThread(() -> new VkAlertDialog.Builder(context)
|
||||
.setTitle(R.string.addinf)
|
||||
@@ -147,17 +119,14 @@ public class FoafBase {
|
||||
.show());
|
||||
} catch (Exception e) {
|
||||
LifecycleUtils.getCurrentActivity().runOnUiThread(() -> makeText(getGlobalContext(), context.getString(R.string.foaferr), LENGTH_SHORT).show());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static long daysPassedFromFoafDate(String str) {
|
||||
try {
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
Date parse = new SimpleDateFormat("yyyy-MM-dd").parse(str.split(" ")[1]);
|
||||
return TimeUnit.DAYS.convert(new Date().getTime() - parse.getTime(), TimeUnit.MILLISECONDS);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ import okhttp3.Request;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ru.vtosters.lite.music.cache;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.text.TextUtils;
|
||||
import bruhcollective.itaysonlab.libvkx.ILibVkxService;
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClientImpl;
|
||||
@@ -17,7 +18,7 @@ public class MusicCacheImpl {
|
||||
track.y1(),
|
||||
track.I != null ? track.I.getId() + "" : "-1",
|
||||
track.f,
|
||||
track.g,
|
||||
!TextUtils.isEmpty(track.g) ? track.g : "",
|
||||
track.C,
|
||||
track.I != null ? track.I.getTitle() : "",
|
||||
track.K,
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
package ru.vtosters.lite.music.converter.ts;
|
||||
|
||||
import com.arthenica.ffmpegkit.FFmpegKit;
|
||||
import com.vk.dto.music.Artist;
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.music.downloader.M3UDownloader;
|
||||
import ru.vtosters.lite.utils.IOUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.Normalizer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class FFMpeg {
|
||||
|
||||
@@ -13,47 +19,26 @@ public class FFMpeg {
|
||||
* @param track Track to be converted
|
||||
* @return True if success, else false
|
||||
*/
|
||||
public static void convert(File in, String out, MusicTrack track) throws Throwable {
|
||||
public static void convert(File in, String out, MusicTrack track) {
|
||||
// convert .ts file to .mp3 file via ffmpeg
|
||||
var cmd = " -y -i \"" + in.getAbsolutePath() + '"'
|
||||
+ " -map 0 -dn"
|
||||
+ " -loglevel error"
|
||||
+ " -hide_banner"
|
||||
+ " -write_id3v2 1"
|
||||
// +" -metadata title=\""+IOUtils.getValidFileName(M3UDownloader.getTitle(track))+'"'
|
||||
// +" -metadata artist=\""+normalizeMetadata(track.L.stream().map(Artist::w1).collect(Collectors.joining(", ")))+'"'
|
||||
// +" -metadata album=\""+normalizeMetadata(track.I.getTitle())+'"'
|
||||
+ setMetadata(track)
|
||||
+ " -c copy \"" + out + '"';
|
||||
var ses = FFmpegKit.execute(cmd);
|
||||
if (ses.getReturnCode().isValueCancel()) throw new RuntimeException(ses.getLogsAsString());
|
||||
}
|
||||
|
||||
private static String normalizeMetadata(String in) {
|
||||
return in.replace('"', '‟');
|
||||
private static String setMetadata(MusicTrack track) {
|
||||
return Preferences.getBoolValue("setMetaData", false) ? " -metadata title=\"" + IOUtils.getValidFileName(M3UDownloader.getTitle(track)) + '"'
|
||||
+ " -metadata artist=\"" + normalizeMetadata(track.L.stream().map(Artist::w1).collect(Collectors.joining(", "))) + '"'
|
||||
+ " -metadata album=\"" + normalizeMetadata(track.I.getTitle()) + '"' : "";
|
||||
}
|
||||
|
||||
// private static void copyAssets()
|
||||
// throws IOException
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// for (var filename:AndroidUtils.getGlobalContext().getAssets().list("ffmpeg"))
|
||||
// if(filename.endsWith(".so"))
|
||||
// IOUtils.writeToFile(
|
||||
// new File(AndroidUtils.getGlobalContext().getFilesDir(),filename),
|
||||
// IOUtils.readFully(AndroidUtils.getGlobalContext().getAssets().open("ffmpeg"+File.separator+filename)));
|
||||
// }
|
||||
// catch(IOException e)
|
||||
// { throw e; }
|
||||
// }
|
||||
//
|
||||
// private static void checkFFMpegLibs()
|
||||
// {
|
||||
// var lib=new File(AndroidUtils.getGlobalContext().getFilesDir(),"libffmpegkit_abidetect.so");
|
||||
// if(!lib.exists())
|
||||
// {
|
||||
// ToastUtils.a(R.string.ffmpegkit_copy);
|
||||
// copyAssets();
|
||||
// }
|
||||
// }
|
||||
private static String normalizeMetadata(String in) {
|
||||
return in.replaceAll("[\\\\/:*?\"<>|]", "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,25 +48,23 @@ public class M3UDownloader
|
||||
var resultMp3 = getResultMp3File(outDir, cache, track);
|
||||
try {
|
||||
CompletableFuture.allOf(createFutures(baseUri, segments, progress, callback, track))
|
||||
.thenRun(() ->
|
||||
{
|
||||
if (cache)
|
||||
.thenRun(() -> {
|
||||
if (cache) {
|
||||
try {
|
||||
ThumbnailDownloader.downloadThumbnails(track);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to download thumbs", e);
|
||||
}
|
||||
}
|
||||
})
|
||||
.thenRun(() ->
|
||||
{
|
||||
.thenRun(() -> {
|
||||
try {
|
||||
TSMerger.merge(getTsesDir(track), resultTs);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException("Failed to merge ts files", e);
|
||||
}
|
||||
})
|
||||
.thenRun(() ->
|
||||
{
|
||||
.thenRun(() -> {
|
||||
try {
|
||||
FFMpeg.convert(resultTs, resultMp3.getAbsolutePath(), track);
|
||||
} catch (Throwable e) {
|
||||
@@ -74,12 +72,18 @@ public class M3UDownloader
|
||||
}
|
||||
})
|
||||
.thenRun(() -> callback.onProgress(10 + Math.round(80.0f * progress.addAndGet(1) / segments.size())))
|
||||
.thenRun(() -> MusicCacheImpl.addTrack(track))
|
||||
.thenRun(() -> {
|
||||
if (cache) {
|
||||
MusicCacheImpl.addTrack(track);
|
||||
}
|
||||
})
|
||||
.whenComplete((unused, tr) -> {
|
||||
if (tr != null) {
|
||||
IOUtils.deleteRecursive(MusicCacheStorageUtils.getTrackDirById(track.y1()));
|
||||
callback.onFailure();
|
||||
} else callback.onSuccess();
|
||||
} else {
|
||||
callback.onSuccess();
|
||||
}
|
||||
IOUtils.deleteRecursive(getTsesDir(track));
|
||||
})
|
||||
.join();
|
||||
@@ -132,7 +136,7 @@ public class M3UDownloader
|
||||
}
|
||||
|
||||
public static String getTitle(MusicTrack track) {
|
||||
return track.f + (!TextUtils.isEmpty(track.g) ? +'(' + track.g + ')' : null);
|
||||
return track.f + (!TextUtils.isEmpty(track.g) ? + '(' + track.g + ')' : "");
|
||||
}
|
||||
|
||||
static File getTsesDir(MusicTrack track) {
|
||||
|
||||
@@ -3,16 +3,19 @@ package ru.vtosters.lite.net;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public final class NetCall {
|
||||
// Constants for the request methods, content types, and encoding
|
||||
private static final String GET = "GET";
|
||||
private static final String POST = "POST";
|
||||
private static final String FORM = "application/x-www-form-urlencoded";
|
||||
private static final String UTF_8 = "UTF-8";
|
||||
|
||||
private final NetRequest req;
|
||||
private final NetClient cl;
|
||||
|
||||
@@ -22,13 +25,17 @@ public final class NetCall {
|
||||
}
|
||||
|
||||
private static String constructArgs(Map<String, String> args) throws UnsupportedEncodingException {
|
||||
// Use a TreeMap to sort the arguments by key
|
||||
args = new TreeMap<>(args);
|
||||
String str = "";
|
||||
for (Map.Entry<String, String> en : args.entrySet()) {
|
||||
if (!str.isEmpty()) str += "&";
|
||||
str += URLEncoder.encode(en.getKey(), "UTF-8") + "=" + URLEncoder.encode(en.getValue(), "UTF-8");
|
||||
// Use a StringBuilder to append the arguments
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : args.entrySet()) {
|
||||
if (sb.length() > 0) sb.append("&");
|
||||
sb.append(URLEncoder.encode(entry.getKey(), UTF_8))
|
||||
.append("=")
|
||||
.append(URLEncoder.encode(entry.getValue(), UTF_8));
|
||||
}
|
||||
return str;
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public NetRequest request() {
|
||||
@@ -38,38 +45,52 @@ public final class NetCall {
|
||||
public NetResponse execute() throws IOException {
|
||||
Proxy proxy = cl.getProxy();
|
||||
PasswordAuthentication auth = cl.getAuthenticator();
|
||||
HttpURLConnection con = (HttpURLConnection) new URL(req.url()).openConnection(proxy != null ? proxy : Proxy.NO_PROXY);
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(req.url()).openConnection(proxy != null ? proxy : Proxy.NO_PROXY);
|
||||
if (proxy != null && auth != null) {
|
||||
// Set the proxy authentication header
|
||||
String authStr = "Basic " + Base64.encodeToString((auth.getUserName() + new String(auth.getPassword())).getBytes(), Base64.NO_WRAP);
|
||||
con.setRequestProperty("Proxy-Connection", "Keep-Alive");
|
||||
con.setRequestProperty("Proxy-Authorization", authStr);
|
||||
connection.setRequestProperty("Proxy-Connection", "Keep-Alive");
|
||||
connection.setRequestProperty("Proxy-Authorization", authStr);
|
||||
}
|
||||
con.setConnectTimeout((int) cl.getTimeout());
|
||||
con.setRequestMethod(req.getRequestMethod());
|
||||
if (req.getRequestMethod().equals("POST")) {
|
||||
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
connection.setConnectTimeout((int) cl.getTimeout());
|
||||
connection.setRequestMethod(req.getRequestMethod());
|
||||
if (req.getRequestMethod().equals(POST)) {
|
||||
// Set the content type for POST requests
|
||||
connection.setRequestProperty("Content-Type", FORM);
|
||||
}
|
||||
Map<String, String> params = req.getRequestParams();
|
||||
if (params != null) {
|
||||
String strArgs = constructArgs(params);
|
||||
con.setRequestProperty("Content-Length", String.valueOf(strArgs.getBytes(StandardCharsets.UTF_8).length));
|
||||
con.setDoOutput(true);
|
||||
con.getOutputStream().write(strArgs.getBytes(StandardCharsets.UTF_8));
|
||||
con.getOutputStream().close();
|
||||
// Write the request parameters to the output stream
|
||||
writeParams(connection, params);
|
||||
}
|
||||
connection.connect();
|
||||
InputStream input;
|
||||
if (connection.getResponseCode() == 200) input = connection.getInputStream();
|
||||
else input = connection.getErrorStream();
|
||||
// Use try-with-resources to close the streams automatically
|
||||
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
||||
byte[] buffer = new byte[1024 * 1024];
|
||||
int count;
|
||||
while ((count = input.read(buffer)) != -1) output.write(buffer, 0, count);
|
||||
input.close();
|
||||
NetResponse response = new NetResponse(output.toByteArray());
|
||||
response.setCode(connection.getResponseCode());
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeParams(HttpURLConnection connection, Map<String, String> params) throws IOException {
|
||||
// Get the encoded arguments string
|
||||
String args = constructArgs(params);
|
||||
// Set the content length header
|
||||
connection.setRequestProperty("Content-Length", String.valueOf(args.getBytes(StandardCharsets.UTF_8).length));
|
||||
// Enable output mode
|
||||
connection.setDoOutput(true);
|
||||
// Write the arguments to the output stream
|
||||
try (OutputStream output = connection.getOutputStream()) {
|
||||
output.write(args.getBytes(StandardCharsets.UTF_8));
|
||||
output.flush();
|
||||
}
|
||||
con.connect();
|
||||
InputStream in;
|
||||
if (con.getResponseCode() == 200) in = con.getInputStream();
|
||||
else in = con.getErrorStream();
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[1024 * 1024];
|
||||
int c;
|
||||
while ((c = in.read(buffer)) != -1) bos.write(buffer, 0, c);
|
||||
in.close();
|
||||
bos.close();
|
||||
NetResponse r = new NetResponse(bos.toByteArray());
|
||||
r.setCode(con.getResponseCode());
|
||||
return r;
|
||||
}
|
||||
|
||||
public void enqueue(NetCallback cb) {
|
||||
@@ -82,12 +103,16 @@ public final class NetCall {
|
||||
} catch (IOException e) {
|
||||
cb.onFailure(NetCall.this, e);
|
||||
}
|
||||
// try {
|
||||
//// interrupt();
|
||||
try {
|
||||
interrupt();
|
||||
join();
|
||||
} catch (Exception e) {
|
||||
Log.e("NetCall", "Failed to interrupt and join thread", e);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
// } catch (Exception e) {
|
||||
// Log.e("NetCall", "Failed to interrupt and join thread", e);
|
||||
// }
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@ public final class NetResponse {
|
||||
private final byte[] data;
|
||||
private int code;
|
||||
|
||||
NetResponse(byte[] data) {
|
||||
public NetResponse(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
void setCode(int code) {
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public class Request {
|
||||
httpURLConnection.setRequestProperty("Content-Type", mIsVTostersRequest ? "Content-Type" : "application/x-www-form-urlencoded");
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
|
||||
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
StringBuilder stringBuffer = new StringBuilder();
|
||||
while (true) {
|
||||
String readLine = bufferedReader.readLine();
|
||||
if (readLine != null) {
|
||||
|
||||
@@ -26,20 +26,20 @@ public class ProfileButtons {
|
||||
newItem = orig.getJSONArray("buttons");
|
||||
}
|
||||
|
||||
if (!VTVerifications.haveDonateButton() && id == AccountManagerUtils.getUserId()) {
|
||||
var map = new HashMap<>();
|
||||
map.put("20", "https://raw.githubusercontent.com/vtosters/lite/main/.github/images/donate_icon/20.png");
|
||||
map.put("40", "https://raw.githubusercontent.com/vtosters/lite/main/.github/images/donate_icon/40.png");
|
||||
map.put("80", "https://raw.githubusercontent.com/vtosters/lite/main/.github/images/donate_icon/80.png");
|
||||
|
||||
newItem.put(generateJsonObject(
|
||||
AndroidUtils.getString(com.vtosters.lite.R.string.donate_to_vtl),
|
||||
"https://vk.com/vtosters_official",
|
||||
"2D81E0",
|
||||
"open_url",
|
||||
map
|
||||
));
|
||||
}
|
||||
// if (!VTVerifications.haveDonateButton() && id == AccountManagerUtils.getUserId()) {
|
||||
// var map = new HashMap<>();
|
||||
// map.put("20", "https://raw.githubusercontent.com/vtosters/lite/main/.github/images/donate_icon/20.png");
|
||||
// map.put("40", "https://raw.githubusercontent.com/vtosters/lite/main/.github/images/donate_icon/40.png");
|
||||
// map.put("80", "https://raw.githubusercontent.com/vtosters/lite/main/.github/images/donate_icon/80.png");
|
||||
//
|
||||
// newItem.put(generateJsonObject(
|
||||
// AndroidUtils.getString(com.vtosters.lite.R.string.donate_to_vtl),
|
||||
// "https://vk.com/vtosters_official",
|
||||
// "2D81E0",
|
||||
// "open_url",
|
||||
// map
|
||||
// ));
|
||||
// }
|
||||
|
||||
if (!orig.has("type") && AccountManagerUtils.isVKTester()) {
|
||||
var map = new HashMap<>();
|
||||
|
||||
@@ -8,6 +8,7 @@ import okhttp3.Response;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
@@ -17,6 +18,8 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
|
||||
public class UsersList {
|
||||
private static final String TAG = "UsersList";
|
||||
private static final List<Integer> descriptionsList = new ArrayList<>();
|
||||
@@ -25,7 +28,7 @@ public class UsersList {
|
||||
public static void getUsersList() {
|
||||
var prefs = AndroidUtils.getGlobalContext().getSharedPreferences("vt_another_data", 0);
|
||||
|
||||
if ((!NetworkUtils.isNetworkConnected() || NetworkUtils.isInternetSlow()) && prefs.contains("ids")) {
|
||||
if ((!NetworkUtils.isNetworkConnected() || NetworkUtils.isInternetSlow()) && prefs.contains("ids") || Preferences.serverFeaturesDisable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,22 +7,7 @@ import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
|
||||
public class TGPref {
|
||||
private static final SharedPreferences Prefs = PreferenceManager.getDefaultSharedPreferences(getGlobalContext());
|
||||
|
||||
private static final String CNCT_METHOD = "VTGS:CM";
|
||||
private static final String TG_BOTKEY = "VTGS:BKey";
|
||||
private static final String TG_PROXYIP = "VTGS:PIP";
|
||||
private static final String TG_PROXYPORT = "VTGS:PPT";
|
||||
private static final String TG_PROXYPASS = "VTGS:PPS";
|
||||
private static final String TG_PROXYUSER = "VTGS:PUS";
|
||||
private static final String TG_PROXYUSEPASS = "VTGS:PUsePassword";
|
||||
|
||||
public static int getTGConnectMethod() {
|
||||
return Integer.parseInt(Prefs.getString(CNCT_METHOD, "0"));
|
||||
}
|
||||
|
||||
public static void setTGConnectMethod(int method) {
|
||||
Prefs.edit().putString(CNCT_METHOD, String.valueOf(method)).apply();
|
||||
}
|
||||
|
||||
public static String getTGBotKey() {
|
||||
return Prefs.getString(TG_BOTKEY, null);
|
||||
@@ -31,40 +16,4 @@ public class TGPref {
|
||||
public static void setTGBotKey(String key) {
|
||||
Prefs.edit().putString(TG_BOTKEY, key).apply();
|
||||
}
|
||||
|
||||
public static String getTGProxyIP() {
|
||||
return Prefs.getString(TG_PROXYIP, null);
|
||||
}
|
||||
|
||||
public static void setTGProxyIP(String ip) {
|
||||
Prefs.edit().putString(TG_PROXYIP, ip).apply();
|
||||
}
|
||||
|
||||
public static int getTGProxyPort() {
|
||||
return Prefs.getInt(TG_PROXYPORT, 0);
|
||||
}
|
||||
|
||||
public static void setTGProxyPort(int port) {
|
||||
Prefs.edit().putInt(TG_PROXYPORT, port).apply();
|
||||
}
|
||||
|
||||
public static String getTGProxyPass() {
|
||||
return Prefs.getString(TG_PROXYPASS, "");
|
||||
}
|
||||
|
||||
public static String getTGProxyUser() {
|
||||
return Prefs.getString(TG_PROXYUSER, "");
|
||||
}
|
||||
|
||||
public static void setTGProxyUserPass(String user, String pass) {
|
||||
Prefs.edit().putString(TG_PROXYUSER, user).putString(TG_PROXYPASS, pass).apply();
|
||||
}
|
||||
|
||||
public static boolean isTGProxyPassEnabled() {
|
||||
return Prefs.getBoolean(TG_PROXYUSEPASS, false);
|
||||
}
|
||||
|
||||
public static void setTGProxyPassEnabled(boolean en) {
|
||||
Prefs.edit().putBoolean(TG_PROXYUSEPASS, en).apply();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,9 @@ package ru.vtosters.lite.tgs;
|
||||
|
||||
import com.aefyr.tsg.g2.TelegramStickersPack;
|
||||
import com.vk.dto.stickers.StickerStockItem;
|
||||
import com.vtosters.lite.R;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
@@ -15,14 +13,6 @@ public class TGRoot {
|
||||
public static final int X = 976820000;
|
||||
public final static Stack<Integer> pendingStickers = new Stack<>();
|
||||
|
||||
public static String getSummary() {
|
||||
return switch (TGPref.getTGConnectMethod()) {
|
||||
case 0 -> AndroidUtils.getString(R.string.ctypedirect);
|
||||
case 2 -> AndroidUtils.getString(R.string.ctypesocks);
|
||||
default -> AndroidUtils.getString(R.string.ctypedisabled);
|
||||
};
|
||||
}
|
||||
|
||||
public static StickerStockItem toStickerPack(TelegramStickersPack p) throws JSONException {
|
||||
JSONArray arr = new JSONArray();
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package ru.vtosters.lite.ui;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.InputType;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
@@ -335,52 +334,6 @@ public class PreferenceFragmentUtils {
|
||||
});
|
||||
}
|
||||
|
||||
public static Preference addEditTextValPreference(
|
||||
PreferenceScreen screen,
|
||||
String key,
|
||||
CharSequence title,
|
||||
CharSequence defval,
|
||||
onPreferenceTextValueChangeListener editTextPrefChangeListener
|
||||
) {
|
||||
return addPreference(screen, key, title, null, null, preference -> {
|
||||
LinearLayout linearLayout = new LinearLayout(screen.getContext());
|
||||
|
||||
final EditText editText = new EditText(screen.getContext());
|
||||
editText.setText(PreferenceManager.getDefaultSharedPreferences(screen.getContext()).getString(key, ""));
|
||||
editText.setHint(title);
|
||||
editText.setTextColor(ThemesUtils.getTextAttr());
|
||||
editText.setHintTextColor(ThemesUtils.getSTextAttr());
|
||||
editText.setText(defval);
|
||||
|
||||
editText.setBackgroundTintList(ThemesUtils.getAccenedColorStateList());
|
||||
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
|
||||
editText.setTransformationMethod(null);
|
||||
|
||||
linearLayout.addView(editText);
|
||||
editText.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
ViewGroup.MarginLayoutParams margin = ((ViewGroup.MarginLayoutParams) editText.getLayoutParams());
|
||||
margin.setMargins(AndroidUtils.dp2px(20f), 0, AndroidUtils.dp2px(20f), 0);
|
||||
editText.setLayoutParams(margin);
|
||||
|
||||
new VkAlertDialog.Builder(screen.getContext())
|
||||
.setTitle(title)
|
||||
.setView(linearLayout)
|
||||
.setPositiveButton("OK", (dialog, which) -> {
|
||||
boolean change = editTextPrefChangeListener.onChanged(preference, editText.getText().toString());
|
||||
if (!change)
|
||||
return;
|
||||
|
||||
PreferenceManager.getDefaultSharedPreferences(screen.getContext())
|
||||
.edit()
|
||||
.putString(key, editText.getText().toString())
|
||||
.apply();
|
||||
})
|
||||
.show();
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
public interface onPreferenceTextValueChangeListener {
|
||||
boolean onChanged(Preference preference, String newValue);
|
||||
}
|
||||
|
||||
@@ -39,11 +39,11 @@ public class IconManager {
|
||||
);
|
||||
|
||||
public static List<String> icons() {
|
||||
return Preferences.hasVerification() && Preferences.isValidSignature() ? sIconsPlusNames : sIconsNames; // delete later sdk check
|
||||
return sIconsPlusNames; // delete later sdk check
|
||||
}
|
||||
|
||||
public static List<String> iconsValues() {
|
||||
return Preferences.hasVerification() && Preferences.isValidSignature() ? sIconsPlus : sIcons; // delete later sdk check
|
||||
return sIconsPlus; // delete later sdk check
|
||||
}
|
||||
|
||||
public static void switchComponent(String icon, String appName) {
|
||||
@@ -55,7 +55,7 @@ public class IconManager {
|
||||
|
||||
Log.d("IconManager", "iconSwitcher: icon = " + icon + ", appname = " + appName);
|
||||
|
||||
List<String> iconsList = (Preferences.hasVerification() && Preferences.isValidSignature()) ? sIconsPlus : sIcons;
|
||||
List<String> iconsList = sIconsPlus;
|
||||
List<String> labelsList = sLabels;
|
||||
|
||||
// check if icon is exist
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
package ru.vtosters.lite.ui.dialogs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import okhttp3.*;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
|
||||
import static android.content.ContentValues.TAG;
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
import static ru.vtosters.hooks.other.Preferences.hasVerification;
|
||||
|
||||
public class ServerDialog {
|
||||
private static final OkHttpClient client = VtOkHttpClient.getInstance();
|
||||
public static Boolean showAlert;
|
||||
private static String title;
|
||||
private static String message;
|
||||
private static String positiveButton;
|
||||
private static String neutralButton;
|
||||
private static String link;
|
||||
private static String key;
|
||||
private static Boolean cancelable;
|
||||
private static Boolean isNotForVerified;
|
||||
|
||||
public static void sendRequest() {
|
||||
if (getBoolValue("dialogrecomm", false)) return;
|
||||
|
||||
if (!getBoolValue("isRoamingState", false)) {
|
||||
Request request = new Request.a()
|
||||
.b("https://vtosters.app/dialog.json")
|
||||
.a();
|
||||
|
||||
client.a(request).a(new Callback() {
|
||||
@Override
|
||||
public void a(Call call, IOException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
showAlert = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(Call call, Response response) {
|
||||
try {
|
||||
getResponse(response.a().g());
|
||||
} catch (Exception e) {
|
||||
showAlert = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static Boolean showForNotVerified() {
|
||||
int random = new Random().nextInt(6);
|
||||
|
||||
if (isNotForVerified) {
|
||||
return !hasVerification() && random != 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void getResponse(String body) throws Exception {
|
||||
JSONObject jSONObject = new JSONObject(body);
|
||||
|
||||
if (jSONObject.getString("title").equals("")) {
|
||||
showAlert = false;
|
||||
return;
|
||||
}
|
||||
|
||||
title = jSONObject.getString("title");
|
||||
message = jSONObject.getString("message");
|
||||
positiveButton = jSONObject.getString("positiveButton");
|
||||
neutralButton = jSONObject.getString("neutralButton");
|
||||
link = jSONObject.getString("link");
|
||||
key = jSONObject.getString("key");
|
||||
cancelable = jSONObject.getBoolean("cancelable");
|
||||
isNotForVerified = jSONObject.getBoolean("isNotForVerified");
|
||||
|
||||
showAlert = true;
|
||||
|
||||
Activity activity = LifecycleUtils.getCurrentActivity();
|
||||
if (getBoolValue(key, true) && showForNotVerified() && showAlert) {
|
||||
activity.runOnUiThread(() -> {
|
||||
new VkAlertDialog.Builder(activity)
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setCancelable(cancelable)
|
||||
.setPositiveButton(positiveButton,
|
||||
(dialogInterface, i) -> Preferences.getPreferences().edit().putBoolean(key, false).apply())
|
||||
.setNeutralButton(neutralButton, (dialogInterface, i) -> {
|
||||
Preferences.getPreferences().edit().putBoolean(key, false).apply();
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW)
|
||||
.setData(Uri.parse(link));
|
||||
activity.startActivity(intent);
|
||||
})
|
||||
.show();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@ package ru.vtosters.lite.ui.fragments;
|
||||
import android.os.Bundle;
|
||||
import androidx.preference.Preference;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
import static ru.vtosters.hooks.other.Preferences.offline;
|
||||
|
||||
public class ActivityFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
@@ -12,6 +14,7 @@ public class ActivityFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
super.onCreate(bundle);
|
||||
addPreferencesFromResource(R.xml.preferences_activity);
|
||||
findPreference("setoffline").setEnabled(offline());
|
||||
findPreference("onlinefixcategory").setVisible(!Preferences.serverFeaturesDisable());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -301,6 +301,20 @@ public class DataSettingsFragment extends TrackedMaterialPreferenceToolbarFragme
|
||||
}
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||
getPreferenceScreen(),
|
||||
"serverFeaturesDisable",
|
||||
"Отключить всю работу с сервером",
|
||||
"Отключает галочки и все дополнительные функции связанные с получением данных с сервера ВТостерс",
|
||||
null,
|
||||
false,
|
||||
(preference, o) -> {
|
||||
Preferences.getPreferences().edit().putBoolean("serverFeaturesDisable", (boolean) o).apply();
|
||||
LifecycleUtils.restartApplicationWithTimer();
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
findPreference("analyticsDisabled").setVisible(Preferences.isValidSignature());
|
||||
}
|
||||
|
||||
|
||||
@@ -92,13 +92,6 @@ public class IconsFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
|
||||
this.addPreferencesFromResource(R.xml.empty);
|
||||
|
||||
if (!Preferences.hasVerification() && !Preferences.getBoolValue("dialogrecomm", false)) {
|
||||
PreferenceFragmentUtils.addPreference(getPreferenceScreen(), "", requireContext().getString(R.string.icons_warning), requireContext().getString(R.string.icons_warning_info), R.drawable.ic_about_outline_28, preference -> {
|
||||
getContext().startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("https://vtosters.app/donate/")));
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), requireContext().getString(R.string.icons_title));
|
||||
|
||||
for (var i = 0; i < IconManager.icons().size(); i++) {
|
||||
@@ -128,37 +121,5 @@ public class IconsFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
if (!Preferences.hasVerification() && !Preferences.getBoolValue("dialogrecomm", false)) {
|
||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), requireContext().getString(R.string.unavailable_icons));
|
||||
|
||||
for (var i = 2; i < IconManager.sIconsPlusNames.size(); i++) {
|
||||
if (IconManager.sIconsPlusNames.get(i) == null || IconManager.sIconsPlus.get(i) == null) return;
|
||||
|
||||
String iconname = IconManager.sIconsPlusNames.get(i);
|
||||
String icon = IconManager.sIconsPlus.get(i);
|
||||
|
||||
int iconRes;
|
||||
|
||||
if (icon.equals("vt")) {
|
||||
iconRes = R.mipmap.vt_launcher_round;
|
||||
} else if (icon.contains("standard")) {
|
||||
iconRes = R.mipmap.ic_launcher_round;
|
||||
} else {
|
||||
iconRes = AndroidUtils.getIdentifier("ic_launcher_" + icon, "mipmap");
|
||||
}
|
||||
|
||||
Drawable drawable = ResourcesCompat.getDrawable(getResources(), iconRes, null);
|
||||
|
||||
if (drawable == null) {
|
||||
drawable = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_bug_outline_28, null);
|
||||
}
|
||||
|
||||
PreferenceFragmentUtils.addPreference(getPreferenceScreen(), icon, iconname, "", drawable, preference -> {
|
||||
AndroidUtils.sendToast(requireContext().getString(R.string.unavailable_icon_warning));
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,13 +13,15 @@ public class InstallGMSFragment extends TrackedMaterialPreferenceToolbarFragment
|
||||
addPreferencesFromResource(R.xml.preferences_gms);
|
||||
|
||||
findPreference("microg").setOnPreferenceClickListener((preference) -> {
|
||||
String[] items = {"Уменьшенный MicroG (Vanced MicroG)", "Полноценный MicroG (Замена GMS)"};
|
||||
String[] items = {"Уменьшенный MicroG (ReVanced)", "Альтернативный MicroG (ReVanced)", "Полноценный MicroG (Замена GMS)"};
|
||||
|
||||
new VkAlertDialog.Builder(requireActivity()).setItems(items, (dialog, which) -> {
|
||||
switch (which) {
|
||||
case 0 ->
|
||||
requireContext().startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("https://github.com/TeamVanced/VancedMicroG/releases/latest/download/microg.apk")));
|
||||
case 1 ->
|
||||
requireContext().startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("https://github.com/inotia00/mMicroG/releases/latest/download/microg.apk")));
|
||||
case 2 ->
|
||||
requireContext().startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("https://github.com/microg/GmsCore/releases")));
|
||||
}
|
||||
dismiss();
|
||||
|
||||
@@ -67,6 +67,13 @@ public class InterfaceFragment extends TrackedMaterialPreferenceToolbarFragment
|
||||
findPreference("showmenu").setVisible(false);
|
||||
}
|
||||
|
||||
var tablet = findPreference("disableForceTabletMode");
|
||||
tablet.setVisible(AndroidUtils.isTablet());
|
||||
tablet.setOnPreferenceClickListener(preference -> {
|
||||
LifecycleUtils.restartApplicationWithTimer();
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("customrounding").setOnPreferenceClickListener(preference -> {
|
||||
RoundingSeekbarDialog.dialog(getContext());
|
||||
return true;
|
||||
|
||||
@@ -4,11 +4,6 @@ import android.app.Activity;
|
||||
import android.content.*;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.view.ContextThemeWrapper;
|
||||
|
||||
import com.guardanis.applock.AppLock;
|
||||
import com.guardanis.applock.activities.LockCreationActivity;
|
||||
import com.vk.auth.api.VKAccount;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
import com.vk.pushes.PushSubscriber;
|
||||
@@ -21,6 +16,8 @@ import ru.vtosters.lite.ssfs.UsersList;
|
||||
import ru.vtosters.lite.ui.activities.VKAdminTokenActivity;
|
||||
import ru.vtosters.lite.utils.*;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
|
||||
public class OtherFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
private static final int VK_ADMIN_TOKEN_REQUEST_CODE = 1;
|
||||
|
||||
@@ -78,22 +75,6 @@ public class OtherFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("pin_setup").setOnPreferenceClickListener(preference -> {
|
||||
var intent = new Intent(this.getActivity(), LockCreationActivity.class);
|
||||
startActivityForResult(intent, AppLock.REQUEST_CODE_LOCK_CREATION);
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("pin_reset").setOnPreferenceClickListener(preference -> {
|
||||
if (AppLock.isEnrolled(requireContext())) {
|
||||
AppLock.getInstance(requireContext()).invalidateEnrollments();
|
||||
AndroidUtils.sendToast(AndroidUtils.getString("pin_reset"));
|
||||
} else {
|
||||
AndroidUtils.sendToast(AndroidUtils.getString("pin_not_set"));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("tokencopy").setOnPreferenceClickListener(preference -> {
|
||||
copyText(AccountManagerUtils.getUserToken());
|
||||
|
||||
@@ -131,6 +112,10 @@ public class OtherFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("VT_Verification").setVisible(!Preferences.serverFeaturesDisable());
|
||||
findPreference("VT_Fire").setVisible(!Preferences.serverFeaturesDisable());
|
||||
findPreference("updateverifdata").setVisible(!Preferences.serverFeaturesDisable());
|
||||
|
||||
var vkAdminTokenPref = findPreference("vk_admin_token");
|
||||
vkAdminTokenPref.setVisible(Preferences.getPreferences().getBoolean("new_music_downloading_way", false));
|
||||
if (vkAdminTokenPref.isVisible()) {
|
||||
|
||||
@@ -218,7 +218,7 @@ public class ThemesFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
requireActivity().runOnUiThread(() -> {
|
||||
dialog.dismiss();
|
||||
new VkAlertDialog.Builder(requireContext())
|
||||
.setTitle(AndroidUtils.getString(R.string.error))
|
||||
.setTitle(AndroidUtils.getString("error"))
|
||||
.setMessage(AndroidUtils.getString("error_applying_accent") + ":\n" + e)
|
||||
.setPositiveButton("OK", null)
|
||||
.show();
|
||||
|
||||
@@ -108,7 +108,7 @@ public class VTSettings extends TrackedMaterialPreferenceToolbarFragment {
|
||||
PowerManager manager = (PowerManager) requireActivity().getSystemService(Context.POWER_SERVICE);
|
||||
boolean isLinksUnverified = AndroidUtils.isLinksUnverified(requireActivity());
|
||||
boolean isDozingAvailable = Build.VERSION.SDK_INT >= 23 && !manager.isIgnoringBatteryOptimizations(AndroidUtils.getPackageName());
|
||||
boolean areNotificationsDisabled = !AndroidUtils.areNotificationsEnabled();
|
||||
boolean areNotificationsDisabled = !AndroidUtils.areNotificationsEnabled() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
|
||||
boolean isGMSNotInstalled = !GmsHook.isAnyServicesInstalled();
|
||||
|
||||
if (AccountManagerUtils.isLogin()) {
|
||||
@@ -142,18 +142,20 @@ public class VTSettings extends TrackedMaterialPreferenceToolbarFragment {
|
||||
});
|
||||
});
|
||||
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
requireContext().getString(R.string.vtssfs),
|
||||
getSSFSsumm(),
|
||||
R.drawable.ic_link_circle_outline_28,
|
||||
preference -> {
|
||||
VKUIwrapper.setLink(Utils.getVKUILink());
|
||||
NavigatorUtils.switchFragment(requireContext(), VKUIwrapper.class);
|
||||
return false;
|
||||
}
|
||||
);
|
||||
if (Preferences.hasSpecialVerif()) {
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
requireContext().getString(R.string.vtssfs),
|
||||
"",
|
||||
R.drawable.ic_link_circle_outline_28,
|
||||
preference -> {
|
||||
VKUIwrapper.setLink(Utils.getVKUILink());
|
||||
NavigatorUtils.switchFragment(requireContext(), VKUIwrapper.class);
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), R.string.appearance_theme_use_system);
|
||||
@@ -649,20 +651,6 @@ public class VTSettings extends TrackedMaterialPreferenceToolbarFragment {
|
||||
}
|
||||
);
|
||||
|
||||
if (!Preferences.hasVerification() && !Preferences.getBoolValue("dialogrecomm", false)) {
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
"Помочь проекту",
|
||||
"За донат можно получить приятные бонусы на аккаунт",
|
||||
R.drawable.ic_money_circle_outline_28,
|
||||
preference -> {
|
||||
requireContext().startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("https://vtosters.app/donate")));
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
@@ -701,6 +689,19 @@ public class VTSettings extends TrackedMaterialPreferenceToolbarFragment {
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||
getPreferenceScreen(),
|
||||
"autoupdates",
|
||||
"Автоматическое обновление",
|
||||
"Получать уведомление о выходе новой версии приложения",
|
||||
R.drawable.ic_history_outline_28,
|
||||
true,
|
||||
(preference, o) -> {
|
||||
Preferences.getPreferences().edit().putBoolean("autoupdates", (boolean) o).apply();
|
||||
return true;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,21 +28,16 @@ import ru.vtosters.lite.ui.adapters.StickerPackAdapter;
|
||||
import ru.vtosters.lite.ui.components.StickerTouchHelperCallback;
|
||||
import ru.vtosters.lite.ui.fragments.BaseToolbarFragment;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.NavigatorUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class StickersFragment extends BaseToolbarFragment {
|
||||
public final static String ACTION_RELOAD = "com.vtosters.lite.action.RELOAD_TGS_LIST";
|
||||
|
||||
final static int TYPE_DIRECT = 0;
|
||||
final static int TYPE_SOCKS = 2;
|
||||
|
||||
public static String ACTION_RELOAD = "com.vtosters.lite.action.RELOAD_TGS_LIST";
|
||||
TelegramStickersGrabber mGrabber;
|
||||
StickerPackAdapter mAdapter;
|
||||
boolean movePending = false;
|
||||
int from, to;
|
||||
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
@@ -59,13 +54,28 @@ public class StickersFragment extends BaseToolbarFragment {
|
||||
}
|
||||
};
|
||||
|
||||
private static void resetToken(Context ctx) {
|
||||
if (TGPref.getTGBotKey() == null) AndroidUtils.sendToast("Токен отсутствует");
|
||||
new VkAlertDialog.Builder(ctx)
|
||||
.setTitle("Сбросить токен бота?")
|
||||
.setNegativeButton(R.string.cancel, (dialog, which) -> {
|
||||
dialog.cancel();
|
||||
})
|
||||
.setPositiveButton(R.string.ok, (dialog, which) -> {
|
||||
TGPref.setTGBotKey(null);
|
||||
AndroidUtils.sendToast("Токен бота сброшен");
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreateMenu(Menu menu) {
|
||||
menu.add(0, 0, 0, "")
|
||||
.setIcon(ThemesUtils.recolorDrawable(requireContext().getDrawable(R.drawable.ic_add_outline_28)))
|
||||
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
menu.add(0, 1, 0, "")
|
||||
.setIcon(R.drawable.ic_settings_outline_28)
|
||||
.setIcon(ThemesUtils.recolorDrawable(requireContext().getDrawable(R.drawable.ic_refresh_outline_28)))
|
||||
.setTitle("Сбросить токен бота")
|
||||
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
super.onCreateMenu(menu);
|
||||
}
|
||||
@@ -74,16 +84,11 @@ public class StickersFragment extends BaseToolbarFragment {
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case 0 -> addTgsPack();
|
||||
case 1 -> openMenu(null);
|
||||
case 1 -> resetToken(requireContext());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void openMenu(String toast) {
|
||||
if (toast != null) Toast.makeText(requireContext(), toast, Toast.LENGTH_SHORT).show();
|
||||
NavigatorUtils.switchFragment(requireContext(), StickersPreferencesFragment.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -96,14 +101,14 @@ public class StickersFragment extends BaseToolbarFragment {
|
||||
public View onCreateContent(@NonNull LayoutInflater inflater, @Nullable Bundle bundle) {
|
||||
setTitle(R.string.vtltgs);
|
||||
|
||||
final var container = new FrameLayout(requireContext());
|
||||
final var recycler = new RecyclerView(requireContext());
|
||||
var container = new FrameLayout(requireContext());
|
||||
var recycler = new RecyclerView(requireContext());
|
||||
|
||||
mAdapter = new StickerPackAdapter();
|
||||
recycler.setAdapter(mAdapter);
|
||||
|
||||
final var callback = new StickerTouchHelperCallback(mAdapter);
|
||||
final var touchHelper = new ItemTouchHelper(callback);
|
||||
var callback = new StickerTouchHelperCallback(mAdapter);
|
||||
var touchHelper = new ItemTouchHelper(callback);
|
||||
touchHelper.attachToRecyclerView(recycler);
|
||||
|
||||
recycler.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
|
||||
@@ -124,80 +129,50 @@ public class StickersFragment extends BaseToolbarFragment {
|
||||
}
|
||||
|
||||
private void addTgsPack() {
|
||||
final var method = TGPref.getTGConnectMethod();
|
||||
if (method != -1) {
|
||||
initGrabber();
|
||||
switch (method) {
|
||||
case TYPE_SOCKS -> {
|
||||
if (TGPref.getTGProxyIP() == null) openMenu(requireContext().getString(R.string.stickersproxy1));
|
||||
}
|
||||
case TYPE_DIRECT -> {
|
||||
initGrabber();
|
||||
final Runnable lambda = () ->
|
||||
initGrabber();
|
||||
Runnable lambda = () -> {
|
||||
var container = new LinearLayout(requireContext());
|
||||
|
||||
var input = new EditText(requireContext());
|
||||
var inputLP = new ViewGroup.MarginLayoutParams(-1, -2);
|
||||
inputLP.setMargins(
|
||||
AndroidUtils.dp2px(24.f),
|
||||
0,
|
||||
AndroidUtils.dp2px(24.f),
|
||||
0);
|
||||
container.addView(input, inputLP);
|
||||
|
||||
new VkAlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.stickershelp1)
|
||||
// .setMessage(R.string.stickershelp2)
|
||||
.setView(container)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) ->
|
||||
{
|
||||
final var container = new LinearLayout(requireContext());
|
||||
var packId = input.getText().toString();
|
||||
if (packId.startsWith("https://"))
|
||||
packId = packId.substring(packId.lastIndexOf('/') + 1);
|
||||
TelegramStickersService.getInstance(requireContext())
|
||||
.requestPackDownload(
|
||||
packId,
|
||||
new File(requireContext().getFilesDir(), "VT-Stickers/" + packId));
|
||||
})
|
||||
.setNeutralButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss())
|
||||
.show();
|
||||
};
|
||||
|
||||
final var input = new EditText(requireContext());
|
||||
final var inputLP = new ViewGroup.MarginLayoutParams(-1, -2);
|
||||
inputLP.setMargins(
|
||||
AndroidUtils.dp2px(24.f),
|
||||
0,
|
||||
AndroidUtils.dp2px(24.f),
|
||||
0);
|
||||
container.addView(input, inputLP);
|
||||
|
||||
new VkAlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.stickershelp1)
|
||||
// .setMessage(R.string.stickershelp2)
|
||||
.setView(container)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) ->
|
||||
{
|
||||
var packId = input.getText().toString();
|
||||
if (packId.startsWith("https://"))
|
||||
packId = packId.substring(packId.lastIndexOf('/') + 1);
|
||||
TelegramStickersService.getInstance(requireContext())
|
||||
.requestPackDownload(
|
||||
packId,
|
||||
new File(requireContext().getFilesDir(), "VT-Stickers/" + packId));
|
||||
})
|
||||
.setNeutralButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss())
|
||||
.show();
|
||||
};
|
||||
|
||||
if (TGPref.getTGBotKey() == null) enterBotKey(() -> checkApiKey(lambda));
|
||||
else checkApiKey(lambda);
|
||||
}
|
||||
}
|
||||
} else openMenu(requireContext().getString(R.string.stickersconnection));
|
||||
if (TGPref.getTGBotKey() == null) enterBotKey(() -> checkApiKey(lambda));
|
||||
else checkApiKey(lambda);
|
||||
}
|
||||
|
||||
private void initGrabber() {
|
||||
switch (TGPref.getTGConnectMethod()) {
|
||||
case TYPE_DIRECT -> {
|
||||
TelegramStickersGrabber.USE_PROXY = false;
|
||||
mGrabber.resetProxy();
|
||||
}
|
||||
case TYPE_SOCKS -> {
|
||||
if (TGPref.getTGProxyIP() == null) break;
|
||||
TelegramStickersGrabber.USE_PROXY = true;
|
||||
TelegramStickersGrabber.PROXY_IP = TGPref.getTGProxyIP();
|
||||
TelegramStickersGrabber.PROXY_PORT = TGPref.getTGProxyPort();
|
||||
if (TGPref.isTGProxyPassEnabled()) {
|
||||
TelegramStickersGrabber.HAS_PASS = true;
|
||||
TelegramStickersGrabber.PROXY_USER = TGPref.getTGProxyUser();
|
||||
TelegramStickersGrabber.PROXY_PASS = TGPref.getTGProxyPass();
|
||||
}
|
||||
mGrabber.enableProxy();
|
||||
}
|
||||
}
|
||||
TelegramStickersGrabber.updateURLs();
|
||||
}
|
||||
|
||||
private void enterBotKey(Runnable callback) {
|
||||
final var container = new LinearLayout(requireContext());
|
||||
var container = new LinearLayout(requireContext());
|
||||
|
||||
final var input = new EditText(requireContext());
|
||||
final var inputLP = new ViewGroup.MarginLayoutParams(-1, -2);
|
||||
var input = new EditText(requireContext());
|
||||
var inputLP = new ViewGroup.MarginLayoutParams(-1, -2);
|
||||
inputLP.setMargins(
|
||||
AndroidUtils.dp2px(24.f),
|
||||
0,
|
||||
@@ -222,7 +197,7 @@ public class StickersFragment extends BaseToolbarFragment {
|
||||
.setMessage(requireContext().getString(R.string.stickersapi9) +
|
||||
requireContext().getString(R.string.stickersapi10))
|
||||
.setNeutralButton(AndroidUtils.getString("open_bot"), (dl, i) -> {
|
||||
final var intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://t.me/botfather"))
|
||||
var intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://t.me/botfather"))
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
requireActivity().startActivity(intent);
|
||||
})
|
||||
@@ -235,7 +210,7 @@ public class StickersFragment extends BaseToolbarFragment {
|
||||
private void checkApiKey(Runnable callback) {
|
||||
mGrabber.setBotApiKey(TGPref.getTGBotKey());
|
||||
|
||||
final var dialog = new ProgressDialog(requireContext());
|
||||
var dialog = new ProgressDialog(requireContext());
|
||||
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||
dialog.setMessage(requireContext().getString(R.string.stickersapi1));
|
||||
dialog.show();
|
||||
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
package ru.vtosters.lite.ui.fragments.tgstickers;
|
||||
|
||||
import android.os.Bundle;
|
||||
import com.aefyr.tsg.g2.stickersgrabber.TelegramStickersGrabber;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.lite.tgs.TGPref;
|
||||
import ru.vtosters.lite.tgs.TGRoot;
|
||||
import ru.vtosters.lite.ui.PreferenceFragmentUtils;
|
||||
import ru.vtosters.lite.ui.fragments.TrackedMaterialPreferenceToolbarFragment;
|
||||
|
||||
public class StickersPreferencesFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
|
||||
int vtosterXml = R.xml.empty;
|
||||
addPreferencesFromResource(vtosterXml);
|
||||
|
||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), requireContext().getString(R.string.sprefsstickers));
|
||||
PreferenceFragmentUtils.addPreference(getPreferenceScreen(), "", R.string.sprefsdelkey, 0, 0, preference -> {
|
||||
TGPref.setTGBotKey(null);
|
||||
ToastUtils.a(requireContext().getString(R.string.sprefsdelkey2));
|
||||
return false;
|
||||
});
|
||||
|
||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), requireContext().getString(R.string.sprefsnetwork));
|
||||
PreferenceFragmentUtils.addListPreference(getPreferenceScreen(), "VTGS:CM", "0", requireContext().getString(R.string.sprefsctype), new CharSequence[]{
|
||||
requireContext().getString(R.string.ctypedirect), requireContext().getString(R.string.ctypesocks)
|
||||
}, new String[]{
|
||||
"0", "2"
|
||||
});
|
||||
|
||||
findPreference("VTGS:CM").setTitle(TGRoot.getSummary());
|
||||
|
||||
findPreference("VTGS:CM").setOnPreferenceChangeListener((preference, o) -> {
|
||||
String newData = (String) o;
|
||||
TGPref.setTGConnectMethod(Integer.parseInt(newData));
|
||||
TelegramStickersGrabber.updateURLs();
|
||||
preference.setTitle(TGRoot.getSummary());
|
||||
return true;
|
||||
});
|
||||
|
||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), R.string.ssocks);
|
||||
|
||||
PreferenceFragmentUtils.addEditTextPreference(getPreferenceScreen(), "tg_proxy_host", R.string.ssockshost, (preference, o) -> {
|
||||
TGPref.setTGProxyIP(o);
|
||||
return true;
|
||||
});
|
||||
PreferenceFragmentUtils.addEditTextPreference(getPreferenceScreen(), "tg_proxy_port", R.string.ssocksport, (preference, o) -> {
|
||||
try {
|
||||
TGPref.setTGProxyPort(Integer.parseInt(o));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
ToastUtils.a(requireContext().getString(R.string.ssockswport));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
PreferenceFragmentUtils.addMaterialSwitchPreference(getPreferenceScreen(), "tg_proxy_auth", requireContext().getString(R.string.ssocksauth), "", 0, false, (preference, o) -> {
|
||||
boolean value = (boolean) o;
|
||||
|
||||
findPreference("tg_proxy_login").setEnabled(value);
|
||||
findPreference("tg_proxy_pass").setEnabled(value);
|
||||
|
||||
TGPref.setTGProxyPassEnabled(value);
|
||||
return true;
|
||||
});
|
||||
PreferenceFragmentUtils.addEditTextPreference(getPreferenceScreen(), "tg_proxy_login", R.string.ssockslogin, (preference, o) -> {
|
||||
TGPref.setTGProxyUserPass(o, TGPref.getTGProxyPass());
|
||||
return true;
|
||||
});
|
||||
PreferenceFragmentUtils.addEditTextPreference(getPreferenceScreen(), "tg_proxy_pass", R.string.ssockspass, (preference, o) -> {
|
||||
TGPref.setTGProxyUserPass(TGPref.getTGProxyUser(), o);
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("tg_proxy_login").setEnabled(TGPref.isTGProxyPassEnabled());
|
||||
findPreference("tg_proxy_pass").setEnabled(TGPref.isTGProxyPassEnabled());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int T4() {
|
||||
return R.string.vtltgs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ import java.nio.ByteBuffer;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
|
||||
enum ImageEffects {
|
||||
Blur(true,
|
||||
AndroidUtils.getArray(R.array.filter_types),
|
||||
Blur(AndroidUtils.getArray(R.array.filter_types),
|
||||
new String[]{"disabled", "low", "med", "high"},
|
||||
getGlobalContext().getString(R.string.filter_blur)
|
||||
) {
|
||||
@@ -40,8 +39,7 @@ enum ImageEffects {
|
||||
};
|
||||
}
|
||||
},
|
||||
Dim(true,
|
||||
AndroidUtils.getArray(R.array.filter_dim_types),
|
||||
Dim(AndroidUtils.getArray(R.array.filter_dim_types),
|
||||
new String[]{"disabled", "dim_black", "dim_white"},
|
||||
getGlobalContext().getString(R.string.filter_dim)) {
|
||||
@Override
|
||||
@@ -66,8 +64,7 @@ enum ImageEffects {
|
||||
};
|
||||
}
|
||||
},
|
||||
Mosaic(true,
|
||||
AndroidUtils.getArray(R.array.filter_types),
|
||||
Mosaic(AndroidUtils.getArray(R.array.filter_types),
|
||||
new String[]{"disabled", "low", "med", "high"},
|
||||
getGlobalContext().getString(R.string.filter_mosaic)) {
|
||||
@Override
|
||||
@@ -94,7 +91,7 @@ enum ImageEffects {
|
||||
};
|
||||
}
|
||||
},
|
||||
Monochrome(false, null, null,
|
||||
Monochrome(null, null,
|
||||
getGlobalContext().getString(R.string.filter_monochrome)) {
|
||||
@Override
|
||||
public void applyEffect(ByteBuffer bitmap, int height, int width) {
|
||||
@@ -103,7 +100,7 @@ enum ImageEffects {
|
||||
}
|
||||
}
|
||||
},
|
||||
Invert(false, null, null,
|
||||
Invert(null, null,
|
||||
getGlobalContext().getString(R.string.filter_invert_colors)) {
|
||||
@Override
|
||||
public void applyEffect(ByteBuffer bitmap, int height, int width) {
|
||||
@@ -112,7 +109,7 @@ enum ImageEffects {
|
||||
}
|
||||
}
|
||||
},
|
||||
Sepia(false, null, null,
|
||||
Sepia(null, null,
|
||||
getGlobalContext().getString(R.string.filter_sepia)) {
|
||||
@Override
|
||||
public void applyEffect(ByteBuffer bitmap, int height, int width) {
|
||||
@@ -121,7 +118,7 @@ enum ImageEffects {
|
||||
}
|
||||
}
|
||||
},
|
||||
Emboss(false, null, null,
|
||||
Emboss(null, null,
|
||||
getGlobalContext().getString(R.string.filter_emboss)) {
|
||||
@Override
|
||||
public String getSummary() {
|
||||
@@ -135,7 +132,7 @@ enum ImageEffects {
|
||||
}
|
||||
}
|
||||
},
|
||||
Engrave(false, null, null,
|
||||
Engrave(null, null,
|
||||
getGlobalContext().getString(R.string.filter_engrave)) {
|
||||
@Override
|
||||
public String getSummary() {
|
||||
@@ -149,7 +146,7 @@ enum ImageEffects {
|
||||
}
|
||||
}
|
||||
},
|
||||
Flea(false, null, null,
|
||||
Flea(null, null,
|
||||
getGlobalContext().getString(R.string.filter_flea)) {
|
||||
@Override
|
||||
public void applyEffect(ByteBuffer bitmap, int height, int width) {
|
||||
@@ -158,7 +155,7 @@ enum ImageEffects {
|
||||
}
|
||||
}
|
||||
},
|
||||
Snow(false, null, null,
|
||||
Snow(null, null,
|
||||
getGlobalContext().getString(R.string.filter_snow)) {
|
||||
@Override
|
||||
public void applyEffect(ByteBuffer bitmap, int height, int width) {
|
||||
@@ -168,15 +165,13 @@ enum ImageEffects {
|
||||
}
|
||||
};
|
||||
|
||||
private final boolean free;
|
||||
private final String title;
|
||||
@Nullable
|
||||
private final String[] entryValues;
|
||||
@Nullable
|
||||
private final String[] entries;
|
||||
|
||||
ImageEffects(boolean free, @Nullable String[] entries, @Nullable String[] entryValues, String title) {
|
||||
this.free = free;
|
||||
ImageEffects(@Nullable String[] entries, @Nullable String[] entryValues, String title) {
|
||||
this.entries = entries;
|
||||
this.entryValues = entryValues;
|
||||
this.title = title;
|
||||
@@ -207,10 +202,6 @@ enum ImageEffects {
|
||||
return entryValues != null && entryValues.length > 0;
|
||||
}
|
||||
|
||||
public boolean isFree() {
|
||||
return free;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String[] getEntries() {
|
||||
return entries;
|
||||
|
||||
@@ -80,24 +80,7 @@ public class WallpaperMenuFragment extends MaterialPreferenceToolbarFragment {
|
||||
|
||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), requireContext().getString(R.string.vtlfilters));
|
||||
|
||||
if (!Preferences.hasVerification() && !Preferences.getBoolValue("dialogrecomm", false)) {
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
requireContext().getString(R.string.filters_warning),
|
||||
requireContext().getString(R.string.icons_warning_info),
|
||||
0,
|
||||
preference -> {
|
||||
requireContext().startActivity(
|
||||
new Intent(Intent.ACTION_VIEW)
|
||||
.setData(Uri.parse("https://vtosters.app/donate/"))
|
||||
);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
Arrays.stream(ImageEffects.values())
|
||||
.filter(imageEffects -> imageEffects.isFree() || Preferences.hasVerification())
|
||||
.forEach(it -> {
|
||||
if (it.isList()) {
|
||||
var pref = PreferenceFragmentUtils.addListPreference(
|
||||
|
||||
@@ -12,13 +12,14 @@ import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import com.vk.core.util.Screen;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
import com.vtosters.lite.general.fragments.WebViewFragment;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -32,6 +33,12 @@ import java.util.Random;
|
||||
|
||||
public class AndroidUtils {
|
||||
private static final String ALLOWED_CHARACTERS = "0123456789qwertyuiopasdfghjklzxcvbnm";
|
||||
public enum ScreenSize {
|
||||
small,
|
||||
normal,
|
||||
large,
|
||||
xlarge
|
||||
}
|
||||
|
||||
public static boolean isDebuggable() {
|
||||
return 0 != (AndroidUtils.getGlobalContext().getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE);
|
||||
@@ -44,7 +51,8 @@ public class AndroidUtils {
|
||||
}
|
||||
|
||||
public static boolean isTablet() {
|
||||
return Screen.l(getGlobalContext());
|
||||
String string = getGlobalContext().getResources().getString(b.h.g.d.screen_size);
|
||||
return TextUtils.equals(string, ScreenSize.large.name()) || TextUtils.equals(string, ScreenSize.xlarge.name());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
||||
@@ -7,10 +7,6 @@ import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import com.guardanis.applock.AppLock;
|
||||
import com.guardanis.applock.activities.UnlockActivity;
|
||||
import com.vk.core.fragments.FragmentImpl;
|
||||
import com.vk.navigation.Navigator;
|
||||
import com.vtosters.lite.MainActivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -46,11 +42,6 @@ public class LifecycleUtils {
|
||||
@Override // android.app.Application.ActivityLifecycleCallbacks
|
||||
public void onActivityCreated(Activity activity, Bundle bundle) {
|
||||
activities.add(activity);
|
||||
|
||||
if (AppLock.isUnlockRequired(activity) && activity.getClass() != MainActivity.class) {
|
||||
var intent = new Intent(activity, UnlockActivity.class);
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override // android.app.Application.ActivityLifecycleCallbacks
|
||||
|
||||
@@ -3,6 +3,7 @@ package ru.vtosters.lite.utils;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
|
||||
import static ru.vtosters.lite.foaf.FoafBase.getBypassedOnlineInfo;
|
||||
|
||||
@@ -13,7 +14,7 @@ public class OnlineBypass {
|
||||
return json;
|
||||
}
|
||||
var onlineinfo = json.optJSONObject("online_info");
|
||||
if (onlineinfo != null && !onlineinfo.optBoolean("visible")) {
|
||||
if (onlineinfo != null && !onlineinfo.optBoolean("visible") && !Preferences.serverFeaturesDisable()) {
|
||||
var bypassed = getBypassedOnlineInfo(id);
|
||||
if (bypassed.optInt("last_seen", 0) != 0) {
|
||||
json.remove("online_info");
|
||||
@@ -37,7 +38,7 @@ public class OnlineBypass {
|
||||
}
|
||||
|
||||
public static JSONArray setOnlineInfoUsers(JSONArray profiles) throws JSONException {
|
||||
if (profiles == null || profiles.length() == 0) return profiles;
|
||||
if (profiles == null || profiles.length() == 0 || Preferences.serverFeaturesDisable()) return profiles;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
var curVkId = AccountManagerUtils.getUserId();
|
||||
for (int i = 0; i < profiles.length(); i++) {
|
||||
@@ -51,7 +52,7 @@ public class OnlineBypass {
|
||||
sb.append(",");
|
||||
}
|
||||
var ids = sb.toString();
|
||||
if (ids.length() > 0) {
|
||||
if (!ids.isEmpty()) {
|
||||
ids = ids.substring(0, ids.length() - 1);
|
||||
} else {
|
||||
return profiles;
|
||||
|
||||
@@ -7,15 +7,14 @@ import okhttp3.*;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
import static ru.vtosters.hooks.other.Preferences.hasVerification;
|
||||
|
||||
public class VTVerifications {
|
||||
public static final List<Integer> sVerifications = new ArrayList<>();
|
||||
@@ -33,7 +32,7 @@ public class VTVerifications {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((!NetworkUtils.isNetworkConnected() && NetworkUtils.isInternetSlow() || getBoolValue("isRoamingState", false)) && prefs.contains("ids")) {
|
||||
if ((!NetworkUtils.isNetworkConnected() && NetworkUtils.isInternetSlow() || getBoolValue("isRoamingState", false)) && prefs.contains("ids") || Preferences.serverFeaturesDisable()) {
|
||||
parseJson(prefs.getString("ids", "[]"));
|
||||
Log.d("VTVerifications", "load from memory. Roaming or Network issues");
|
||||
isLoaded = true;
|
||||
@@ -129,7 +128,7 @@ public class VTVerifications {
|
||||
return -id;
|
||||
}
|
||||
|
||||
public static boolean haveDonateButton() {
|
||||
return hasVerification() || new Random().nextInt(6) != 1;
|
||||
}
|
||||
// public static boolean haveDonateButton() {
|
||||
// return hasVerification() || new Random().nextInt(6) != 1;
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
||||
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
|
||||
@@ -198,14 +197,6 @@
|
||||
android:name="ru.vtosters.lite.ui.activities.VKAdminTokenActivity"
|
||||
android:launchMode="singleTop">
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.guardanis.applock.activities.LockCreationActivity"
|
||||
android:launchMode="singleTop">
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.guardanis.applock.activities.UnlockActivity"
|
||||
android:launchMode="singleTop">
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.vtosters.lite.MainActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||
|
||||
+1
-1
@@ -25,5 +25,5 @@ usesFramework:
|
||||
tag: null
|
||||
version: 2.6.0
|
||||
versionInfo:
|
||||
versionCode: '4838'
|
||||
versionCode: '4839'
|
||||
versionName: 5.56.1
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:drawable="@color/applock__create_choose_option_bg_pressed" android:state_selected="true"/>
|
||||
<item android:drawable="@color/applock__create_choose_option_bg_pressed" android:state_pressed="true"/>
|
||||
<item android:drawable="@color/applock__create_choose_option_bg" />
|
||||
|
||||
</selector>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.9 KiB |
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/applock__activity_lock_creation"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/applock__activity_padding">
|
||||
|
||||
<include
|
||||
android:id="@+id/pin__container"
|
||||
layout="@layout/applock__lock_creation" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/applock__activity_unlock"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/applock__activity_padding">
|
||||
|
||||
<include
|
||||
android:id="@+id/pin__container"
|
||||
layout="@layout/applock__unlock" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<EditText
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="1dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:cursorVisible="false"
|
||||
android:imeOptions="flagNoExtractUi|actionDone"
|
||||
android:inputType="number"
|
||||
android:textColor="@android:color/transparent"/>
|
||||
@@ -1,20 +0,0 @@
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:applock="http://schemas.android.com/apk/res-auto"
|
||||
style="@style/applock__content_parent"
|
||||
android:descendantFocusability="beforeDescendants"
|
||||
android:focusableInTouchMode="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pin__description"
|
||||
style="@style/applock__description" />
|
||||
|
||||
<com.guardanis.applock.pin.PINInputView
|
||||
android:id="@+id/pin__input_view"
|
||||
style="@style/applock__input_pin_view"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/pin__action_settings"
|
||||
style="@style/applock__action_settings"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1,20 +0,0 @@
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:applock="http://schemas.android.com/apk/res-auto"
|
||||
style="@style/applock__content_parent"
|
||||
android:descendantFocusability="beforeDescendants"
|
||||
android:focusableInTouchMode="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pin__description"
|
||||
style="@style/applock__description"/>
|
||||
|
||||
<com.guardanis.applock.pin.PINInputView
|
||||
android:id="@+id/pin__input_view"
|
||||
style="@style/applock__input_pin_view"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/pin__action_settings"
|
||||
style="@style/applock__action_settings"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -5981,6 +5981,7 @@
|
||||
<string name="any_bank_card">Карта любога банка</string>
|
||||
<string name="current_place_number">Нумар бягучага месца</string>
|
||||
<string name="eight_friends">Гуляе 8 Вашых сяброў</string>
|
||||
|
||||
<string name="vtlfeed">Стужка</string>
|
||||
<string name="vtlinterface">Інтэрфейс</string>
|
||||
<string name="vtlmedia">Медыякантэнт</string>
|
||||
@@ -6066,7 +6067,7 @@
|
||||
<string name="gms_download_microg">Спампаваць MicroG</string>
|
||||
<string name="gms_what_to_do_next">Што рабіць далей?</string>
|
||||
<string name="gms_what_to_do_after_microg_title">Што рабіць пасля ўстаноўкі MicroG?</string>
|
||||
<string name="gms_what_to_do_after_microg_summ">1. Увайдзіце ў свой Google акаўнт \n2. Пераўсталюеце прыкладанне VTLite</string>
|
||||
<string name="gms_what_to_do_after_microg_summ">1. Увайдзіце ў свой Google рахунак на наладах MicroG\n2. Уключыце рэгістрацыю прылады\n3. Уключыце воблачны абмен паведамленнямі\n4. Пераўсталюеце VTLite\n5. Дазвольце яму прымаць паведамлення</string>
|
||||
<string name="donate">Дапамагчы праекту</string>
|
||||
<string name="fulltime">dd MMMM yyyy у HH:mm:ss</string>
|
||||
<string name="fulltime2">dd MMMM у HH:mm:ss</string>
|
||||
@@ -6096,7 +6097,7 @@
|
||||
<string name="BGStickerssum">Для ўключэння/адключэння вам неабходна ачысціць кэш прыкладання</string>
|
||||
<string name="addinf">дадатковая інфармацыя</string>
|
||||
<string name="copyid">Скапіяваць ID</string>
|
||||
<string name="vtssfs">VT Функцыі</string>
|
||||
<string name="vtssfs">Серверныя функцыі</string>
|
||||
<string name="vticon">Іконка дадатку</string>
|
||||
<string name="vticonbtn">Выкарыстоўваць арыгінальную іконку</string>
|
||||
<string name="vticonsummary">Выкарыстанне арыгінальнай назвы і іконкі дадатку як у афіцыйнага кліента VK</string>
|
||||
@@ -6310,7 +6311,7 @@
|
||||
<string name="friendsblock_title">Схаваць сяброў</string>
|
||||
<string name="friendsblock_summ">Схаваць блок рэкамендацый сяброў у сябрах</string>
|
||||
<string name="onlineformatter_title">Пашыраны анлайн</string>
|
||||
<string name="onlineformatter_summ">Паказваць з якога прыкладання/кліента чалавек у анлайне</string>
|
||||
<string name="onlineformatter_summ">Паказваць з якога прыкладання/кліента чалавек у анлайне\n\nНапрыклад: Онлайн З дапамогай Kate Mobile</string>
|
||||
<string name="voices_vtl">Галасавыя паведамленні</string>
|
||||
<string name="disable_voice_listening_summ">Функцыя дазваляе не адпраўляць статут праслухоўвання галасавых
|
||||
паведамленняў чалавека вамі
|
||||
|
||||
@@ -5420,7 +5420,7 @@
|
||||
<string name="gms_download_microg">Скачать MicroG</string>
|
||||
<string name="gms_what_to_do_next">Что делать дальше?</string>
|
||||
<string name="gms_what_to_do_after_microg_title">Что делать после установки MicroG?</string>
|
||||
<string name="gms_what_to_do_after_microg_summ">1. Войдите в свой Google аккаунт в MicroG \n2. Переустановите приложение VTLite</string>
|
||||
<string name="gms_what_to_do_after_microg_summ">1. Войдите в свой Google аккаунт в настройках MicroG \n2. Включите регистрацию устройства \n3. Включите облачный обмен сообщениями \n4. Переустановите VTLite \n5. Разрешите ему принимать уведомления</string>
|
||||
<string name="donate">Помочь проекту</string>
|
||||
<string name="fulltime">dd MMMM yyyy в HH:mm:ss</string>
|
||||
<string name="fulltime2">dd MMMM в HH:mm:ss</string>
|
||||
@@ -5446,7 +5446,7 @@
|
||||
<string name="BGStickerssum">Для включения/отключения вам необходимо очистить кеш приложения</string>
|
||||
<string name="addinf">Дополнительная информация</string>
|
||||
<string name="copyid">Скопировать айди</string>
|
||||
<string name="vtssfs">VT Функции</string>
|
||||
<string name="vtssfs">Серверные функции</string>
|
||||
<string name="vticon">Иконка приложения</string>
|
||||
<string name="vticonbtn">Использовать оригинальную иконку</string>
|
||||
<string name="vticonsummary">Использование оригинального названия и иконки приложения как у официального клиента ВК</string>
|
||||
@@ -5640,7 +5640,7 @@
|
||||
<string name="friendsblock_title">Скрыть друзей</string>
|
||||
<string name="friendsblock_summ">Скрыть блок рекомендаций друзей в друзьях</string>
|
||||
<string name="onlineformatter_title">Расширенный онлайн</string>
|
||||
<string name="onlineformatter_summ">Показывать с какого приложения/клиента человек в онлайне</string>
|
||||
<string name="onlineformatter_summ">Показывать с какого приложения/клиента человек в онлайне\n\nНапример: Онлайн с помощью Kate Mobile</string>
|
||||
<string name="voices_vtl">Голосовые сообщения</string>
|
||||
<string name="disable_voice_listening_summ">Функция позволяет не отправлять статус прослушивания голосовых сообщений человека вами</string>
|
||||
<string name="listen_v_title">Отключить статус прослушивания</string>
|
||||
@@ -6364,37 +6364,6 @@
|
||||
<string name="device_info_copied">Информация об устройстве скопирована</string>
|
||||
<string name="app_open_by_default_settings">Для нормальной работы приложения необходимо разрешить приложению открытие ссылок по умолчанию</string>
|
||||
|
||||
<string name="applock__description_chooser">Защитить это приложение с помощью PIN-кода или отпечатка пальцев?</string>
|
||||
<string name="applock__description_create_pin">Создайте PIN-код для защиты этого приложения</string>
|
||||
<string name="applock__description_create_pin_reattempt">Неверный PIN-код. Попробуйте еще раз</string>
|
||||
<string name="applock__description_create_fingerprint">Используйте свой отпечаток пальца, чтобы защитить это приложение</string>
|
||||
<string name="applock__description_create_fingerprint_paused">Разблокировка по биометрии отменена. Попробуйте снова</string>
|
||||
<string name="applock__description_confirm">Введите PIN-код для подтверждения</string>
|
||||
<string name="applock__description_unlock_pin">Введите свой PIN-код для разблокировки</string>
|
||||
<string name="applock__description_unlock_fingerprint">Приложите палец к сканеру</string>
|
||||
<string name="applock__description_unlock_fingerprint_help">Проблема при распознавании отпечатка пальца: %1$s</string>
|
||||
<string name="applock__create_chooser_option_pin">PIN</string>
|
||||
<string name="applock__create_chooser_option_fingerprint">Отпечаток пальца</string>
|
||||
<string name="applock__unlock_error_no_matching_pin_found">Не существует сохраненного PIN-кода для разблокировки</string>
|
||||
<string name="applock__unlock_error_match_failed">Неверный PIN-код!</string>
|
||||
<string name="applock__unlock_error_insufficient_selection">Неправильное количество цифр! Пожалуйста, попробуйте еще раз</string>
|
||||
<string name="applock__unlock_error_retry_limit_exceeded">Слишком много неудачных попыток. Попробуйте снова через %1$s</string>
|
||||
<string name="applock__toast_unlock_required">Вы не можете этого сделать</string>
|
||||
<string name="applock__password_char">*</string>
|
||||
<string name="applock__action_settings">Открыть системные настройки</string>
|
||||
<string name="applock__fingerprint_alias">AppLock</string>
|
||||
<string name="applock__fingerprint_error_not_enrolled">Вы не настроили разблокировку по отпечатку пальца</string>
|
||||
<string name="applock__fingerprint_error_unrecognized">Ваш отпечаток пальца не был распознан</string>
|
||||
<string name="applock__fingerprint_error_unknown">Произошло что-то странное</string>
|
||||
<string name="applock__fingerprint_error_none">Отпечатки пальцев не найдены! Добавьте их в системных настройках</string>
|
||||
<string name="applock__fingerprint_error_hardware">Отсутствует сканер отпечатков пальцев</string>
|
||||
<string name="applock__fingerprint_error_permission">Требуется разрешение на использование отпечатков пальцев</string>
|
||||
<string name="applock__fingerprint_error_permission_multiple">Разрешение на работу с биометрией не было получено. Выдайте его приложению в системных настройках</string>
|
||||
<item name="applock__empty_item_min_size_percent" format="float" type="string">0.2</item>
|
||||
|
||||
<string name="pin_not_set">PIN-код не установлен</string>
|
||||
<string name="pin_reset">PIN-код был успешно сброшен</string>
|
||||
|
||||
<string name="failed_to_get_text">Ошибка получения текста</string>
|
||||
<string name="error_no_text">Ошибка получения текста, возможно текст не найден</string>
|
||||
<string name="applying_accent">Применение акцента</string>
|
||||
|
||||
@@ -5347,7 +5347,7 @@
|
||||
<string name="gms_download_microg">Завантажити MicroG</string>
|
||||
<string name="gms_what_to_do_next">Що робити далі?</string>
|
||||
<string name="gms_what_to_do_after_microg_title">Що робити після встановлення MicroG?</string>
|
||||
<string name="gms_what_to_do_after_microg_summ">1. Увійдіть до свого облікового запису Google \n2. Перевстановіть додаток VTLite"</string>
|
||||
<string name="gms_what_to_do_after_microg_summ">"1. Увійдіть у свій обліковий запис Google у налаштуваннях MicroG\n2. Увімкніть реєстрацію пристрою\n3. Увімкніть Хмарний обмін повідомленнями\n4. Перевстановіть VTLite\n5. Дозвольте йому приймати повідомлення"</string>
|
||||
<string name="donate">Допомогти проекту</string>
|
||||
<string name="fulltime">dd MMMM yyyy в HH:mm:ss</string>
|
||||
<string name="fulltime2">dd MMMM в HH:mm:ss</string>
|
||||
@@ -5373,7 +5373,7 @@
|
||||
<string name="BGStickerssum">Для увімкнення/вимкнення вам необхідно очистити кеш додатка</string>
|
||||
<string name="addinf">додаткова інформація</string>
|
||||
<string name="copyid">Копіювати ID</string>
|
||||
<string name="vtssfs">VT Функції</string>
|
||||
<string name="vtssfs">Серверні функції</string>
|
||||
<string name="vticon">Іконка додатку</string>
|
||||
<string name="vticonbtn">Використовувати оригінальну іконку</string>
|
||||
<string name="vticonsummary">Використання оригінальної назви та іконки додатку як у офіційного клієнта ВК</string>
|
||||
@@ -5567,7 +5567,7 @@
|
||||
<string name="friendsblock_title">Приховати друзів</string>
|
||||
<string name="friendsblock_summ">Приховати блок рекомендацій друзів у друзях</string>
|
||||
<string name="onlineformatter_title">Розширений онлайн</string>
|
||||
<string name="onlineformatter_summ">Показувати з якого додатка/клієнта людина в онлайні</string>
|
||||
<string name="onlineformatter_summ">Показувати з якого додатка/клієнта людина в онлайні\n\nНаприклад: Онлайн за допомогою Kate Mobile</string>
|
||||
<string name="voices_vtl">Голосові повідомлення</string>
|
||||
<string name="disable_voice_listening_summ">Функція дозволяє не надсилати статус прослуховування голосових повідомлень вами</string>
|
||||
<string name="listen_v_title">Вимкнути статус прослуховування</string>
|
||||
|
||||
@@ -2511,8 +2511,4 @@
|
||||
<attr name="im_ic_msgreload" format="reference" />
|
||||
<attr name="im_ic_msgdl" format="reference" />
|
||||
<attr name="im_ic_stats" format="reference" />
|
||||
<declare-styleable name="PINInputView">
|
||||
<attr name="pinTextColor" format="reference|color"/>
|
||||
<attr name="pinBackgroundColor" format="reference|color"/>
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
|
||||
@@ -17,7 +17,4 @@
|
||||
<bool name="spb_default_reversed">false</bool>
|
||||
<bool name="vk_is_tablet">false</bool>
|
||||
<bool name="com_samsung_android_icon_container_has_icon_container">true</bool>
|
||||
<bool name="applock__unlock_activity_return_allowed">false</bool>
|
||||
<bool name="applock__item_password_chars_enabled">true</bool>
|
||||
<bool name="applock__fingerprint_service_enabled">true</bool>
|
||||
</resources>
|
||||
|
||||
@@ -686,15 +686,4 @@
|
||||
<color name="yellow_light">#ffffd54f</color>
|
||||
<color name="yellow_sunflower">#fffece00</color>
|
||||
<color name="iclauncher">#fffcfcfc</color>
|
||||
|
||||
<color name="applock__activity_background">#FAFAFA</color>
|
||||
<color name="applock__description_text">#7F8C8D</color>
|
||||
|
||||
<color name="applock__item_background">#3C9ADF</color>
|
||||
<color name="applock__item_text">#FAFAFA</color>
|
||||
|
||||
<color name="applock__create_choose_option_bg">#00FFFFFF</color>
|
||||
<color name="applock__create_choose_option_bg_pressed">#11000000</color>
|
||||
|
||||
<color name="applock__action_settings">#95A5A6</color>
|
||||
</resources>
|
||||
|
||||
@@ -855,20 +855,4 @@
|
||||
<item name="wrap_content" type="dimen">-2</item>
|
||||
<dimen name="year_label_height">64.0dip</dimen>
|
||||
<dimen name="year_label_text_size">22.0dip</dimen>
|
||||
|
||||
<dimen name="applock__activity_padding">24dip</dimen>
|
||||
<dimen name="applock__content_padding_horizontal">24dip</dimen>
|
||||
<dimen name="applock__content_padding_vertical">36dip</dimen>
|
||||
<dimen name="applock__item_margin_top">20dip</dimen>
|
||||
<dimen name="applock__item_size">50dip</dimen>
|
||||
<dimen name="applock__fingerprint_scan_image_margin_top">35dip</dimen>
|
||||
<dimen name="applock__fingerprint_scan_image_size">65dip</dimen>
|
||||
<dimen name="applock__chooser_image_size">50dip</dimen>
|
||||
<dimen name="applock__chooser_parent_padding_vertical">24dip</dimen>
|
||||
<dimen name="applock__chooser_text_padding_top">12dip</dimen>
|
||||
<dimen name="applock__description_text">18dip</dimen>
|
||||
<dimen name="applock__description_padding_bottom">20dip</dimen>
|
||||
<dimen name="applock__action_settings">14dip</dimen>
|
||||
<dimen name="applock__action_settings_padding">12dip</dimen>
|
||||
<dimen name="applock__action_settings_margin_top">24dip</dimen>
|
||||
</resources>
|
||||
|
||||
@@ -3919,10 +3919,6 @@
|
||||
<item name="download_mp3" type="id" />
|
||||
<item name="remove_from_cache_vkx" type="id" />
|
||||
<item name="add_to_cache_vkx" type="id" />
|
||||
<item name="pin__description" type="id" />
|
||||
<item name="pin__action_settings" type="id" />
|
||||
<item name="pin__input_view" type="id" />
|
||||
<item name="pin__container" type="id"/>
|
||||
<item name="account_backup_view" type="id" />
|
||||
<item name="copy_image" type="id" />
|
||||
</resources>
|
||||
|
||||
@@ -43,9 +43,4 @@
|
||||
<integer name="status_bar_notification_info_maxnum">999</integer>
|
||||
<integer name="vkim_activity_animation_duration">200</integer>
|
||||
<integer name="vkim_playing_drawable_rect_count">4</integer>
|
||||
|
||||
<integer name="applock__input_pin_item_count">4</integer>
|
||||
<integer name="applock__max_retry_count">5</integer>
|
||||
<integer name="applock__failure_retry_delay">5</integer>
|
||||
<integer name="applock__activity_lock_reenable_minutes">1440</integer>
|
||||
</resources>
|
||||
|
||||
@@ -5554,7 +5554,7 @@ Filters are not case-sensitive!"</string>
|
||||
<string name="gms_download_microg">Download MicroG</string>
|
||||
<string name="gms_what_to_do_next">What to do next?</string>
|
||||
<string name="gms_what_to_do_after_microg_title">What to do after installing MicroG?</string>
|
||||
<string name="gms_what_to_do_after_microg_summ">1. Log in to your Google account \n2. Reinstall VTLite application</string>
|
||||
<string name="gms_what_to_do_after_microg_summ">1. Log in to your Google account in the MicroG settings\n2. Enable device registration\n3. Enable cloud messaging\n4. Reinstall VTLite\n5. Allow him to receive notifications</string>
|
||||
<string name="donate">Donate</string>
|
||||
<string name="fulltime">dd MMMM yyyy HH:mm:ss</string>
|
||||
<string name="fulltime2">dd MMMM HH:mm:ss</string>
|
||||
@@ -5580,7 +5580,7 @@ Does not affect vk.cc links"</string>
|
||||
<string name="BGStickerssum">You need to clear the application cache after toggling this option</string>
|
||||
<string name="addinf">Additional information</string>
|
||||
<string name="copyid">Copy ID</string>
|
||||
<string name="vtssfs">VT Features</string>
|
||||
<string name="vtssfs">Server features</string>
|
||||
<string name="vticon">App Icon</string>
|
||||
<string name="vticonbtn">Use original icon</string>
|
||||
<string name="vticonsummary">The original name and icon of VK</string>
|
||||
@@ -5615,7 +5615,7 @@ Warning! It can cause long downloads of user lists if there are a lot of users i
|
||||
<string name="ctypesocks">Socks</string>
|
||||
<string name="dnr">Do not read</string>
|
||||
<string name="dns">Disable status of viewing</string>
|
||||
<string name="dnw">Do not write</string>
|
||||
<string name="dnw">Do not type</string>
|
||||
<string name="docknumbers">Counters in dockbar</string>
|
||||
<string name="docknumberssum">"Disabling doesn't work in the tablet interface"</string>
|
||||
<string name="dockbar_tab_titles">Show dockbar item titles</string>
|
||||
@@ -5774,7 +5774,7 @@ You need to restart the application to apply proxy settings"</string>
|
||||
<string name="friendsblock_title">Hide friends</string>
|
||||
<string name="friendsblock_summ">Hide the block of recommendations of friends in friends section</string>
|
||||
<string name="onlineformatter_title">Extended online indicator</string>
|
||||
<string name="onlineformatter_summ">Show what app/device a person is online from</string>
|
||||
<string name="onlineformatter_summ">Show what app/device a person is online from\n\nFor example: Online using Kate Mobile</string>
|
||||
<string name="voices_vtl">Voice messages</string>
|
||||
<string name="disable_voice_listening_summ">The function allows you not to send the status of listening to the person\'s voice messages by you</string>
|
||||
<string name="listen_v_title">Disable listening status</string>
|
||||
@@ -5879,7 +5879,7 @@ May look like a fake leaving the online"</string>
|
||||
|
||||
<string name="activity_what_is_it">What is it?</string>
|
||||
<string name="activity_dnr_summary">Function lets you don\'t send read message status</string>
|
||||
<string name="activity_dnw_summary">Function lets you don\'t send write message status</string>
|
||||
<string name="activity_dnw_summary">Function lets you don\'t send type message status</string>
|
||||
<string name="activity_dns_summary">Function lets you don\'t send read stories status</string>
|
||||
|
||||
<string name="activity_dnr_visual">Visually may not work correctly (locally read), but companion will see that it wasn\'t read.</string>
|
||||
@@ -6502,37 +6502,6 @@ May look like a fake leaving the online"</string>
|
||||
<string name="device_info_copied">Device info copied</string>
|
||||
<string name="app_open_by_default_settings">You need to allow the app to open links by default for the app to work properly</string>
|
||||
|
||||
<string name="applock__description_chooser">Secure this application with a PIN or your fingerprints?</string>
|
||||
<string name="applock__description_create_pin">Create a PIN to secure this application</string>
|
||||
<string name="applock__description_create_pin_reattempt">PINs didn\'t match. Try again</string>
|
||||
<string name="applock__description_create_fingerprint">Scan your fingerprint to secure this application</string>
|
||||
<string name="applock__description_create_fingerprint_paused">Fingerprint authentication canceled. Reload this content to restart</string>
|
||||
<string name="applock__description_confirm">Re-enter your PIN to confirm</string>
|
||||
<string name="applock__description_unlock_pin">Enter your PIN to unlock</string>
|
||||
<string name="applock__description_unlock_fingerprint">Scan your fingerprint to unlock</string>
|
||||
<string name="applock__description_unlock_fingerprint_help">We\'re having trouble recognizing your fingerprint: %1$s</string>
|
||||
<string name="applock__create_chooser_option_pin">PIN</string>
|
||||
<string name="applock__create_chooser_option_fingerprint">Fingerprint</string>
|
||||
<string name="applock__unlock_error_no_matching_pin_found">There is no saved PIN to unlock</string>
|
||||
<string name="applock__unlock_error_match_failed">The PINs don\'t match!</string>
|
||||
<string name="applock__unlock_error_insufficient_selection">Wrong number of digits! Please try again</string>
|
||||
<string name="applock__unlock_error_retry_limit_exceeded">You failed too many times. You may try again in %1$s</string>
|
||||
<string name="applock__toast_unlock_required">You can\'t do that</string>
|
||||
<string name="applock__password_char">*</string>
|
||||
<string name="applock__action_settings">Open System Settings</string>
|
||||
<string name="applock__fingerprint_alias">AppLock</string>
|
||||
<string name="applock__fingerprint_error_not_enrolled">You haven\'t setup fingerprint unlocking</string>
|
||||
<string name="applock__fingerprint_error_unrecognized">Your fingerprint wasn\'t recognized</string>
|
||||
<string name="applock__fingerprint_error_unknown">Something weird happened</string>
|
||||
<string name="applock__fingerprint_error_none">No fingerprints found! Enable them in your system settings</string>
|
||||
<string name="applock__fingerprint_error_hardware">Missing fingerprint hardware?</string>
|
||||
<string name="applock__fingerprint_error_permission">Fingerprint permission required</string>
|
||||
<string name="applock__fingerprint_error_permission_multiple">Fingerprint permission denied. Please enable fingerprint support in your system settings</string>
|
||||
<item name="applock__empty_item_min_size_percent" format="float" type="string">0.2</item>
|
||||
|
||||
<string name="pin_not_set">PIN not set</string>
|
||||
<string name="pin_reset">PIN has been successfully reset</string>
|
||||
|
||||
<string name="failed_to_get_text">Failed to get text</string>
|
||||
<string name="error_no_text">Error receiving text, possibly no text found</string>
|
||||
<string name="applying_accent">Applying accent</string>
|
||||
|
||||
@@ -10262,47 +10262,4 @@
|
||||
<item name="android:shadowDy">-1.0</item>
|
||||
<item name="android:shadowRadius">0.25</item>
|
||||
</style>
|
||||
|
||||
<style name="applock__content_parent">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:gravity">center_horizontal</item>
|
||||
<item name="android:orientation">vertical</item>
|
||||
<item name="android:paddingLeft">@dimen/applock__content_padding_horizontal</item>
|
||||
<item name="android:paddingTop">@dimen/applock__content_padding_vertical</item>
|
||||
<item name="android:paddingRight">@dimen/applock__content_padding_horizontal</item>
|
||||
<item name="android:paddingBottom">@dimen/applock__content_padding_vertical</item>
|
||||
</style>
|
||||
|
||||
<style name="applock__description">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:text">These is some kind of instructions you should follow.</item>
|
||||
<item name="android:textColor">?text_primary</item>
|
||||
<item name="android:textSize">@dimen/applock__description_text</item>
|
||||
</style>
|
||||
|
||||
<style name="applock__input_pin_view">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">@dimen/applock__item_size</item>
|
||||
<item name="android:layout_marginTop">@dimen/applock__item_margin_top</item>
|
||||
</style>
|
||||
|
||||
<style name="applock__input_fingerprint_view">
|
||||
<item name="android:layout_width">@dimen/applock__fingerprint_scan_image_size</item>
|
||||
<item name="android:layout_height">@dimen/applock__fingerprint_scan_image_size</item>
|
||||
<item name="android:layout_marginTop">@dimen/applock__fingerprint_scan_image_margin_top</item>
|
||||
</style>
|
||||
|
||||
<style name="applock__action_settings">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_marginTop">@dimen/applock__action_settings_margin_top</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:padding">@dimen/applock__action_settings_padding</item>
|
||||
<item name="android:text">@string/applock__action_settings</item>
|
||||
<item name="android:textColor">?text_primary</item>
|
||||
<item name="android:textSize">@dimen/applock__action_settings</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
android:key="listen_v"
|
||||
android:title="@string/listen_v_title"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/vkme_online_vtl">
|
||||
<PreferenceCategory android:title="@string/vkme_online_vtl" android:key="onlinefixcategory">
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="onlinefix"
|
||||
|
||||
@@ -94,6 +94,11 @@
|
||||
android:key="pollresults"
|
||||
android:summary="@string/pollresults_summ"
|
||||
android:title="@string/pollresults_title"/>
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="disableForceTabletMode"
|
||||
android:summary="Отключает интерфейс для планшетов и возвращает докбар"
|
||||
android:title="Отключить режим планшета"/>
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="friendsblock"
|
||||
|
||||
@@ -45,6 +45,11 @@
|
||||
android:entryValues="@array/musicdefcatalog"
|
||||
android:key="musicdefcatalog"
|
||||
android:title="@string/musicdefcatalog_title"/>
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="setMetaData"
|
||||
android:summary="Сохранять id3v2 теги для песен для MP3 (Экспериментально)"
|
||||
android:title="Сохранять метадату песен"/>
|
||||
<Preference
|
||||
android:key="audio_download"
|
||||
android:title="@string/audio_download_title"/>
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceCategory android:title="PIN-код">
|
||||
<Preference
|
||||
android:key="pin_setup"
|
||||
android:title="Установить PIN"/>
|
||||
<Preference
|
||||
android:key="pin_reset"
|
||||
android:title="Сбросить PIN"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/other_fix_app">
|
||||
<Preference
|
||||
android:key="firebasefix"
|
||||
@@ -18,25 +10,12 @@
|
||||
android:title="@string/microgsett"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/vtverify">
|
||||
<Preference
|
||||
android:enabled="false"
|
||||
android:summary="@string/vtverifyinfosum"
|
||||
android:title="@string/vtverifyinfo"/>
|
||||
<Preference
|
||||
android:persistent="false"
|
||||
android:summary="vtosters.app/donate"
|
||||
android:title="@string/getvtverify">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="https://vtosters.app/donate"/>
|
||||
</Preference>
|
||||
<Preference
|
||||
android:key="updateverifdata"
|
||||
android:summary="@string/updateverifdata_summ"
|
||||
android:title="@string/updateverifdata_title"/>
|
||||
<Preference
|
||||
android:key="copyownlink"
|
||||
android:summary="@string/copyownlink_summ"
|
||||
android:title="@string/copyownlink_title"/>
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="true"
|
||||
|
||||
@@ -354,6 +354,16 @@
|
||||
.method static a(Landroid/content/Context;Ljava/lang/String;)V
|
||||
.locals 11
|
||||
|
||||
const-string v0, "hideDeviceInfo"
|
||||
|
||||
sget-object v1, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean;
|
||||
|
||||
invoke-static {v0, v1}, Lru/vtosters/hooks/other/Preferences;->getBoolValue(Ljava/lang/String;Ljava/lang/Boolean;)Z
|
||||
|
||||
move-result v0
|
||||
|
||||
if-nez v0, :cond_1
|
||||
|
||||
if-eqz p0, :cond_0
|
||||
|
||||
if-eqz p1, :cond_0
|
||||
|
||||
@@ -1088,31 +1088,10 @@
|
||||
.end annotation
|
||||
.end param
|
||||
|
||||
.line 1
|
||||
invoke-static {p0}, Lcom/vk/core/util/Screen;->f(Landroid/content/Context;)Lcom/vk/core/util/Screen$ScreenSize;
|
||||
|
||||
move-result-object p0
|
||||
|
||||
invoke-virtual {p0}, Ljava/lang/Enum;->ordinal()I
|
||||
invoke-static {}, Lru/vtosters/hooks/TabletHook;->hook()Z
|
||||
|
||||
move-result p0
|
||||
|
||||
sget-object v0, Lcom/vk/core/util/Screen$ScreenSize;->normal:Lcom/vk/core/util/Screen$ScreenSize;
|
||||
|
||||
invoke-virtual {v0}, Ljava/lang/Enum;->ordinal()I
|
||||
|
||||
move-result v0
|
||||
|
||||
if-le p0, v0, :cond_0
|
||||
|
||||
const/4 p0, 0x1
|
||||
|
||||
goto :goto_0
|
||||
|
||||
:cond_0
|
||||
const/4 p0, 0x0
|
||||
|
||||
:goto_0
|
||||
return p0
|
||||
.end method
|
||||
|
||||
|
||||
@@ -546,8 +546,6 @@
|
||||
invoke-virtual {p0, p1, v0}, Landroidx/fragment/app/FragmentActivity;->startActivityForResult(Landroid/content/Intent;I)V
|
||||
|
||||
:goto_1
|
||||
invoke-static {p0}, Lru/vtosters/hooks/MainActivityInjector;->applock(Landroid/app/Activity;)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
const-string v0, "func_v"
|
||||
|
||||
const/16 v1, 0x1b
|
||||
const/16 v1, 0x25
|
||||
|
||||
.line 3
|
||||
invoke-virtual {p0, v0, v1}, Lcom/vk/api/base/ApiRequest;->b(Ljava/lang/String;I)Lcom/vk/api/base/ApiRequest;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user