Compare commits

..
Author SHA1 Message Date
gdlbo cdaf7909d4 fix old android crash accenting 2023-07-04 23:23:18 +03:00
gdlbo c70ab388c1 fixed account saving 2023-07-04 22:55:22 +03:00
gdlbo 50c66c2703 fix music metrics 2023-07-04 19:56:12 +03:00
gdlbo 357e520bb0 some code fixes 2023-07-04 18:57:06 +03:00
gdlbo 6379ce5741 cleanup code 2023-07-04 13:42:04 +03:00
Vologhat 02807739a1 fix #1394 2023-07-02 22:32:26 +03:00
gdlbo 40635ab75a fix #1388 2023-07-02 13:44:47 +03:00
gdlbo 32e1bfe6fd fix messages color accent 2023-07-02 00:04:10 +03:00
26 changed files with 281 additions and 298 deletions
@@ -28,6 +28,7 @@ import com.vtosters.lite.data.ThemeTracker;
import ru.vtosters.lite.deviceinfo.OEMDetector;
import ru.vtosters.lite.themes.ThemesCore;
import ru.vtosters.lite.themes.ThemesHacks;
import ru.vtosters.lite.themes.ThemesManager;
import ru.vtosters.lite.ui.wallpapers.WallpapersHooks;
import ru.vtosters.lite.utils.LifecycleUtils;
import ru.vtosters.lite.utils.WebViewColoringUtils;
@@ -59,7 +60,7 @@ public class ThemesUtils {
activity = LifecycleUtils.getCurrentActivity();
}
VKThemeHelper.theme(theme, activity, fl);
if (isMonetTheme()) ThemesCore.clear();
if (isMonetTheme() || ThemesManager.canApplyCustomAccent()) ThemesCore.clear();
if (restartActivity) activity.recreate();
ThemeTracker.a();
WebViewColoringUtils.isLoaded = false;
@@ -11,15 +11,15 @@ public class ImBanner {
private static final String TAG = "ImBanner";
public static JSONObject convertToBanner(JSONObject original) {
final String PEER = "peer";
final String ID = "id";
final String PICTURE = "picture";
final String TEXT = "text";
final String LINK = "link";
final String LINK_TEXT = "link_text";
final String NAME = "name";
final String BUTTONS = "buttons";
final String ICON = "icon";
String PEER = "peer";
String ID = "id";
String PICTURE = "picture";
String TEXT = "text";
String LINK = "link";
String LINK_TEXT = "link_text";
String NAME = "name";
String BUTTONS = "buttons";
String ICON = "icon";
Optional<JSONObject> user = Optional.ofNullable(original.optJSONObject(PEER));
int userId = user.map(u -> u.optInt(ID)).orElse(0);
@@ -166,26 +166,25 @@ public class ThemesCore {
}
public static boolean hasThemedAttr(Context context, int attrID) {
if (ThemesUtils.isMonetTheme()) {
if (Preferences.getBoolValue("logColors", false)) {
try {
Log.d(TAG, "Requesting color by attr " + context.getResources().getResourceName(attrID));
} catch (Exception ignored) {
}
if (Preferences.getBoolValue("logColors", false)) {
try {
Log.d(TAG, "Requesting color by attr " + context.getResources().getResourceName(attrID));
} catch (Exception ignored) {
}
}
if (ThemesUtils.isMonetTheme() || ThemesManager.canApplyCustomAccent()) {
if (isCachedAccents()) {
if (ThemesUtils.isDarkTheme()) {
return (themedColors.get(attrID) != 0 && ACCENT_THEME_ONLY_DARK.get(attrID, true) && (
ThemesUtils.isMilkshake() ?
ACCENT_THEME_ONLY_MILK_DARK.get(attrID, true) :
ACCENT_THEME_ONLY_NOMILK_DARK.get(attrID, true)));
} else {
return (themedColors.get(attrID) != 0 && ACCENT_THEME_ONLY_LIGHT.get(attrID, true) && (
ThemesUtils.isMilkshake() ?
ACCENT_THEME_ONLY_MILK_LIGHT.get(attrID, true) :
ACCENT_THEME_ONLY_NOMILK_LIGHT.get(attrID, true)));
}
boolean isDark = ThemesUtils.isDarkTheme();
boolean isMilkshake = ThemesUtils.isMilkshake();
SparseBooleanArray themeOnlyMap = isDark ? ACCENT_THEME_ONLY_DARK : ACCENT_THEME_ONLY_LIGHT;
SparseBooleanArray milkshakeMap = isDark ? ACCENT_THEME_ONLY_MILK_DARK : ACCENT_THEME_ONLY_MILK_LIGHT;
SparseBooleanArray noMilkshakeMap = isDark ? ACCENT_THEME_ONLY_NOMILK_DARK : ACCENT_THEME_ONLY_NOMILK_LIGHT;
return (themedColors.get(attrID) != 0 && themeOnlyMap.get(attrID, true) && (
isMilkshake ?
milkshakeMap.get(attrID, true) :
noMilkshakeMap.get(attrID, true)));
} else {
return themedColors.get(attrID) != 0;
}
@@ -194,7 +193,6 @@ public class ThemesCore {
}
}
public static void clear() {
cachedAccents = false;
themedColors.clear();
@@ -20,7 +20,7 @@ import java.util.zip.ZipOutputStream;
public class ThemesManager {
private final static int[] ACCENT_COLORS = {
private static final int[] ACCENT_COLORS = {
R.color.vk_sky_300,
R.color.sky_300,
R.color.viewer_retry_button_text_color,
@@ -96,7 +96,7 @@ public class ThemesManager {
R.color.header_blue_opacity40
};
// modify it if "doNotCompress" in apktool.yml has been edited
private final static String[] DO_NOT_COMPRESS = {
private static final String[] DO_NOT_COMPRESS = {
".png",
".jpg",
".mp3",
@@ -124,14 +124,13 @@ public class ThemesManager {
ResourcesLoader.load(app, modApk.getAbsolutePath(), false);
}
} catch (Exception e) {
Log.e("ThemesManager", e.getMessage());
e.printStackTrace();
}
}
// validate modded apk before loading
private static void validateModApk()
throws IOException {
final var apk = new ZipFile(modApk);
private static void validateModApk() throws IOException {
var apk = new ZipFile(modApk);
apk.close();
validated = true;
@@ -153,23 +152,18 @@ public class ThemesManager {
return validated && modApk.exists() && ThemesUtils.getReservedAccent() != Color.TRANSPARENT;
}
public static void generateModApk(int accentColor)
throws Throwable {
try (
final var apk = new ZipFile(baseApkPath)
) {
final var arscEntry = apk.getEntry("resources.arsc");
final var arscBis = new BufferedInputStream(apk.getInputStream(arscEntry));
final var arsc = BinaryResourceFile.fromInputStream(arscBis);
public static void generateModApk(int accentColor) throws Throwable {
try (var apk = new ZipFile(baseApkPath)) {
var arscEntry = apk.getEntry("resources.arsc");
var arscBis = new BufferedInputStream(apk.getInputStream(arscEntry));
var arsc = BinaryResourceFile.fromInputStream(arscBis);
ArscEditor.changeColors(arsc, ACCENT_COLORS, accentColor);
try (
final var zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(modApk)))
) {
final var arscBuff = arsc.toByteArray();
final var newArscEntry = new ZipEntry("resources.arsc");
try (var zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(modApk)))) {
var arscBuff = arsc.toByteArray();
var newArscEntry = new ZipEntry("resources.arsc");
final var crc = new CRC32();
var crc = new CRC32();
crc.update(arscBuff);
newArscEntry.setSize(arscBuff.length);
@@ -180,10 +174,10 @@ public class ThemesManager {
zos.write(arscBuff);
zos.closeEntry();
final var entries = apk.entries();
var entries = apk.entries();
while (entries.hasMoreElements()) {
final var entry = entries.nextElement();
final var name = entry.getName();
var entry = entries.nextElement();
var name = entry.getName();
if (!name.startsWith("res/") && !name.startsWith("assets/") || name.equals("resources.arsc"))
continue;
@@ -196,8 +190,8 @@ public class ThemesManager {
}
}
final var entryBis = new BufferedInputStream(apk.getInputStream(entry));
final var newEntry = new ZipEntry(name);
var entryBis = new BufferedInputStream(apk.getInputStream(entry));
var newEntry = new ZipEntry(name);
if (doNotCompress) {
newEntry.setMethod(ZipEntry.STORED);
@@ -1,59 +1,44 @@
package ru.vtosters.lite.themes.loaders;
import android.annotation.SuppressLint;
import android.content.res.AssetManager;
import android.util.Log;
import ru.vtosters.lite.utils.ReflectionUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@SuppressLint("PrivateApi")
public class AssetManagerHelper {
// methods
private final static Method getAssetPathMtd;
private final static Method getApkAssetsMtd;
private final static Method addAssetPathMtd;
private final static Method addAssetPathAsSharedLibraryMtd;
private final static Method addOverlayPathMtd;
static {
try {
getAssetPathMtd = ReflectionUtils.findMethod(Class.forName("android.content.res.ApkAssets"), "getAssetPath");
getApkAssetsMtd = ReflectionUtils.findMethod(AssetManager.class, "getApkAssets");
addAssetPathMtd = AssetManager.class.getMethod("addAssetPath", String.class);
addAssetPathAsSharedLibraryMtd = AssetManager.class.getMethod("addAssetPathAsSharedLibrary", String.class);
addOverlayPathMtd = AssetManager.class.getMethod("addOverlayPath", String.class);
} catch (ClassNotFoundException | NoSuchMethodException e) {
throw new RuntimeException();
}
}
public static String getApkPath(Object assetManager, String packagename)
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Object[] apkAssetsArr = (Object[]) getAssetPathMtd.invoke(assetManager);
public static String getApkPath(Object assetManager, String packagename) throws InvocationTargetException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException {
Object[] apkAssetsArr = (Object[]) ReflectionUtils.findMethod(Class.forName("android.content.res.ApkAssets"), "getAssetPath").invoke(assetManager);
// By default, base apk is the last element of array if is not, for execution speed, we should iterate array from the end to the beginning
for (int i = apkAssetsArr.length - 1; i >= 0; i--) {
final String pathname = (String) getApkAssetsMtd.invoke(apkAssetsArr[i]);
if (pathname.contains(packagename)) return pathname;
String pathname = (String) ReflectionUtils.findMethod(AssetManager.class, "getApkAssets").invoke(apkAssetsArr[i]);
if (pathname != null && pathname.contains(packagename)) return pathname;
}
throw new NullPointerException();
}
//region Uses for adding own assets or getting existing cookies
public static int addAssetPath(AssetManager manager, String path)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
return (int) addAssetPathMtd.invoke(manager, path);
public static void addAssetPath(AssetManager manager, String path) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
manager.getClass().getMethod("addAssetPath", String.class).invoke(manager, path);
}
public static int addAssetPathAsSharedLibrary(AssetManager manager, String path)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
return (int) addAssetPathAsSharedLibraryMtd.invoke(manager, path);
public static int addAssetPathAsSharedLibrary(AssetManager manager, String path) {
try {
return (int) AssetManager.class.getMethod("addAssetPathAsSharedLibrary", String.class).invoke(manager, path);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
public static int addOverlayPath(AssetManager manager, String path)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
return (int) addOverlayPathMtd.invoke(manager, path);
public static int addOverlayPath(AssetManager manager, String path) {
try {
return (int) AssetManager.class.getMethod("addOverlayPath", String.class).invoke(manager, path);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
//endregion
}
@@ -1,5 +1,6 @@
package ru.vtosters.lite.themes.loaders;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.AssetManager;
@@ -13,17 +14,19 @@ import ru.vtosters.lite.utils.ReflectionUtils;
import java.io.File;
import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@SuppressLint("PrivateApi")
public class ResourcesLoader {
private static Collection<WeakReference<Resources>> sResourceReferences = null;
private static Object sCurrentActivityThread = null;
private static AssetManager sAssetManager = null;
// methods
private static Method ensureStringBlocksMtd = null;
@@ -42,7 +45,7 @@ public class ResourcesLoader {
static {
try {
// API version 8 has PackageInfo, 10 has LoadedApk. Needs to check 9
final Class<?> activityThreadClz = Class.forName("android.app.ActivityThread");
Class<?> activityThreadClz = Class.forName("android.app.ActivityThread");
Class<?> loadedApkClz;
try {
loadedApkClz = Class.forName("android.app.LoadedApk");
@@ -87,43 +90,40 @@ public class ResourcesLoader {
}
}
public static void init(Context context)
throws Exception {
public static void init(Context context) throws Exception {
sCurrentActivityThread = ReflectionUtils.getActivityThread(context, null);
//pre-N
// Find the singleton instance of ResourcesManager
final Class<?> resourcesManagerClass = Class.forName("android.app.ResourcesManager");
final Method mGetInstance = ReflectionUtils.findMethod(resourcesManagerClass, "getInstance");
final Object resourcesManager = mGetInstance.invoke(null);
Class<?> resourcesManagerClass = Class.forName("android.app.ResourcesManager");
Method mGetInstance = ReflectionUtils.findMethod(resourcesManagerClass, "getInstance");
Object resourcesManager = mGetInstance.invoke(null);
try {
Field fMActiveResources = ReflectionUtils.findField(resourcesManagerClass, "mActiveResources");
final ArrayMap<?, WeakReference<Resources>> activeResources19 =
ArrayMap<?, WeakReference<Resources>> activeResources19 =
(ArrayMap<?, WeakReference<Resources>>) fMActiveResources.get(resourcesManager);
sResourceReferences = activeResources19.values();
} catch (NoSuchFieldException ignore) {
// N moved the resources to mResourceReferences
final Field mResourceReferences = ReflectionUtils.findField(resourcesManagerClass, "mResourceReferences");
Field mResourceReferences = ReflectionUtils.findField(resourcesManagerClass, "mResourceReferences");
sResourceReferences = (Collection<WeakReference<Resources>>) mResourceReferences.get(resourcesManager);
}
}
public static void load(Context context, String resPath, boolean reinject)
throws Exception {
final ApplicationInfo appInfo = context.getApplicationInfo();
public static void load(Context context, String resPath, boolean reinject) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException, NoSuchMethodException {
ApplicationInfo appInfo = context.getApplicationInfo();
final Field[] packagesFlds = Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1
Field[] packagesFlds = Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1
? new Field[]{packagesFld, resourcePackagesFld}
: new Field[]{packagesFld};
for (var fld : packagesFlds) {
final var value = fld.get(sCurrentActivityThread);
var value = fld.get(sCurrentActivityThread);
for (var entry
: ((Map<String, WeakReference<?>>) value).entrySet()) {
final var loadedApk = entry.getValue().get();
for (var entry : ((Map<String, WeakReference<?>>) value).entrySet()) {
var loadedApk = entry.getValue().get();
if (loadedApk == null) continue;
final var resDirPath = (String) resDirFld.get(loadedApk);
var resDirPath = (String) resDirFld.get(loadedApk);
if (appInfo.sourceDir.equals(resDirPath))
resDirFld.set(loadedApk, resPath);
}
@@ -134,10 +134,10 @@ public class ResourcesLoader {
return;
}
sAssetManager = AssetManager.class.newInstance();
// Create a new AssetManager instance and point it to the resources installed under
if (AssetManagerHelper.addAssetPath(sAssetManager, resPath) == 0)
throw new IllegalStateException("Could not create new AssetManager");
AssetManager sAssetManager = AssetManager.class.newInstance();
AssetManagerHelper.addAssetPath(sAssetManager, resPath);
// Add SharedLibraries to AssetManager for resolve system resources not found issue
// This influence SharedLibrary Package ID
@@ -157,7 +157,7 @@ public class ResourcesLoader {
ensureStringBlocksMtd.invoke(sAssetManager);
}
for (var wr : sResourceReferences) {
final var resources = wr.get();
var resources = wr.get();
if (resources == null) continue;
// Set the AssetManager of the Resources instance to our brand new one
@@ -166,9 +166,9 @@ public class ResourcesLoader {
assetsFld.set(resources, sAssetManager);
} catch (Throwable ignore) {
// N
final var resourceImpl = resourcesImplFld.get(resources);
var resourceImpl = resourcesImplFld.get(resources);
// for Huawei HwResourcesImpl
final Field implAssets = ReflectionUtils.findField(resourceImpl, "mAssets");
Field implAssets = ReflectionUtils.findField(resourceImpl, "mAssets");
implAssets.set(resourceImpl, sAssetManager);
}
@@ -196,13 +196,13 @@ public class ResourcesLoader {
private static void installResourceInsuranceHacks(Context context, String patchedResApkPath) {
try {
final Object activityThread = ReflectionUtils.getActivityThread(context, null);
final Field mHField = ReflectionUtils.findField(activityThread, "mH");
final Handler mH = (Handler) mHField.get(activityThread);
final Field mCallbackField = ReflectionUtils.findField(Handler.class, "mCallback");
final Handler.Callback originCallback = (Handler.Callback) mCallbackField.get(mH);
Object activityThread = ReflectionUtils.getActivityThread(context, null);
Field mHField = ReflectionUtils.findField(activityThread, "mH");
Handler mH = (Handler) mHField.get(activityThread);
Field mCallbackField = ReflectionUtils.findField(Handler.class, "mCallback");
Handler.Callback originCallback = (Handler.Callback) mCallbackField.get(mH);
if (!(originCallback instanceof ResourceInsuranceHandlerCallback)) {
final ResourceInsuranceHandlerCallback hackCallback = new ResourceInsuranceHandlerCallback(
ResourceInsuranceHandlerCallback hackCallback = new ResourceInsuranceHandlerCallback(
context, patchedResApkPath, originCallback, mH.getClass());
mCallbackField.set(mH, hackCallback);
} else {
@@ -250,9 +250,9 @@ public class ResourcesLoader {
Log.w("ResourcesLoader", "try to clear typedArray cache!");
// Clear typedArray cache.
try {
final Field typedArrayPoolField = ReflectionUtils.findField(Resources.class, "mTypedArrayPool");
final Object origTypedArrayPool = typedArrayPoolField.get(resources);
final Method acquireMethod = ReflectionUtils.findMethod(origTypedArrayPool, "acquire");
Field typedArrayPoolField = ReflectionUtils.findField(Resources.class, "mTypedArrayPool");
Object origTypedArrayPool = typedArrayPoolField.get(resources);
Method acquireMethod = ReflectionUtils.findMethod(origTypedArrayPool, "acquire");
while (true) {
if (acquireMethod.invoke(origTypedArrayPool) == null) {
break;
@@ -268,9 +268,8 @@ public class ResourcesLoader {
applicationInfo.sharedLibraryFiles != null;
}
private static final class ResourceInsuranceHandlerCallback implements Handler.Callback {
private static class ResourceInsuranceHandlerCallback implements Handler.Callback {
private static final String LAUNCH_ACTIVITY_LIFECYCLE_ITEM_CLASSNAME = "android.app.servertransaction.LaunchActivityItem";
private final Context mContext;
private final String mPatchResApkPath;
private final Handler.Callback mOriginalCallback;
@@ -319,48 +318,56 @@ public class ResourcesLoader {
}
@SuppressWarnings("unchecked")
private boolean hackMessage(Message msg) {
boolean shouldReInjectPatchedResources = false;
// A method to check if the message requires re-injecting patched resources
private boolean shouldReInjectPatchedResources(Message msg) {
if (!isPatchedResModifiedAfterLastLoad(mPatchResApkPath)) {
shouldReInjectPatchedResources = false;
} else {
if (msg.what == LAUNCH_ACTIVITY || msg.what == RELAUNCH_ACTIVITY) {
shouldReInjectPatchedResources = true;
} else if (msg.what == EXECUTE_TRANSACTION) {
do {
if (mSkipInterceptExecuteTransaction) {
break;
}
final Object transaction = msg.obj;
if (transaction == null) {
Log.w("ResourcesLoader", "transaction is null, skip rest insurance logic.");
break;
}
if (mGetCallbacksMethod == null) {
try {
mGetCallbacksMethod = ReflectionUtils.findMethod(transaction, "getCallbacks");
} catch (Throwable ignored) {
// Ignored.
}
}
if (mGetCallbacksMethod == null) {
Log.e("ResourcesLoader", "fail to find getLifecycleStateRequest method, skip rest insurance logic.");
mSkipInterceptExecuteTransaction = true;
break;
}
try {
final List<Object> req = (List<Object>) mGetCallbacksMethod.invoke(transaction);
if (req != null && req.size() > 0) {
final Object cb = req.get(0);
shouldReInjectPatchedResources = cb != null && cb.getClass().getName().equals(LAUNCH_ACTIVITY_LIFECYCLE_ITEM_CLASSNAME);
}
} catch (Throwable ignored) {
Log.e("ResourcesLoader", "fail to call getLifecycleStateRequest method, skip rest insurance logic.");
}
} while (false);
return false;
}
if (msg.what == LAUNCH_ACTIVITY || msg.what == RELAUNCH_ACTIVITY) {
return true;
}
// If the message is executing a transaction, check the callbacks
if (msg.what == EXECUTE_TRANSACTION) {
// Skip the logic if the method is not found or an error occurs
if (mSkipInterceptExecuteTransaction) {
return false;
}
// Get the transaction object from the message
Object transaction = msg.obj;
if (transaction == null) {
Log.w("ResourcesLoader", "transaction is null, skip rest insurance logic.");
return false;
}
// Get the getCallbacks method from the transaction class
if (mGetCallbacksMethod == null) {
try {
mGetCallbacksMethod = ReflectionUtils.findMethod(transaction, "getCallbacks");
} catch (Throwable ignored) {
// Ignored.
}
}
if (mGetCallbacksMethod == null) {
Log.e("ResourcesLoader", "fail to find getCallbacks method, skip rest insurance logic.");
mSkipInterceptExecuteTransaction = true;
return false;
}
try {
List<Object> callbacks = (List<Object>) mGetCallbacksMethod.invoke(transaction);
if (callbacks != null && !callbacks.isEmpty()) {
Object cb = callbacks.get(0);
return cb != null && cb.getClass().getName().equals(LAUNCH_ACTIVITY_LIFECYCLE_ITEM_CLASSNAME);
}
} catch (Throwable ignored) {
Log.e("ResourcesLoader", "fail to call getCallbacks method, skip rest insurance logic.");
}
}
if (shouldReInjectPatchedResources) {
return false;
}
// A method to hack the message and re-inject patched resources if needed
@SuppressWarnings("unchecked")
private boolean hackMessage(Message msg) {
if (shouldReInjectPatchedResources(msg)) {
try {
load(mContext, mPatchResApkPath, true);
} catch (Throwable thr) {
@@ -23,8 +23,8 @@ import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
public class PalettesManager {
private final static File PALETTES_DIR = new File(Environment.getExternalStorageDirectory(), "VTL/palettes");
private final static String ASSETS_DIR = "vtl_themes/palettes/";
private static final File PALETTES_DIR = new File(Environment.getExternalStorageDirectory(), "VTL/palettes");
private static final String ASSETS_DIR = "vtl_themes/palettes/";
private static PalettesManager sInstance;
@@ -51,17 +51,17 @@ public class PalettesManager {
return;
}
final var palettes = PALETTES_DIR.listFiles((dir, name) -> name.endsWith(".json"));
var palettes = PALETTES_DIR.listFiles((dir, name) -> name.endsWith(".json"));
if (palettes == null || palettes.length == 0)
copyPaletteFromAssets();
parsePalettes();
}
private boolean copyPaletteFromAssets() {
private void copyPaletteFromAssets() {
try {
final var manager = AndroidUtils.getGlobalContext().getAssets();
final var assets = manager.list(ASSETS_DIR);
if (assets == null || assets.length == 0) return false;
var manager = AndroidUtils.getGlobalContext().getAssets();
var assets = manager.list(ASSETS_DIR);
if (assets == null || assets.length == 0) return;
for (var asset : assets) {
try {
IOUtils.copy(manager.open(ASSETS_DIR + asset), new File(PALETTES_DIR, asset));
@@ -69,11 +69,9 @@ public class PalettesManager {
e.printStackTrace();
}
}
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
private void parsePalettes() {
@@ -8,15 +8,15 @@ public class ArscEditor {
public static void changeColors(BinaryResourceFile arsc, int[] colorIds, int color) {
for (var chunk : arsc.getChunks()) {
final var resTableChunk = (ResourceTableChunk) chunk;
var resTableChunk = (ResourceTableChunk) chunk;
for (var packageChunk : resTableChunk.getPackages()) {
for (var typeChunk : packageChunk.getTypeChunks("color")) {
for (var entry : typeChunk.getEntries().entrySet()) {
final var value = entry.getValue();
var value = entry.getValue();
if (value.isComplex()) continue;
final var binValue = value.value();
var binValue = value.value();
if (!isColorResourceValue(binValue)) continue;
final var resId = packageChunk.getId() << 24 | typeChunk.getId() << 16 | entry.getKey();
var resId = packageChunk.getId() << 24 | typeChunk.getId() << 16 | entry.getKey();
for (var colodId : colorIds) {
if (resId == colodId) {
binValue.data = color;
@@ -301,7 +301,7 @@ public class PreferenceFragmentUtils {
return addPreference(screen, key, title, null, null, preference -> {
LinearLayout linearLayout = new LinearLayout(screen.getContext());
final EditText editText = new EditText(screen.getContext());
EditText editText = new EditText(screen.getContext());
editText.setText(PreferenceManager.getDefaultSharedPreferences(screen.getContext()).getString(key, ""));
editText.setHint(title);
editText.setTextColor(ThemesUtils.getTextAttr());
@@ -36,7 +36,7 @@ public class CategorizedAdapter<T> extends RecyclerView.Adapter<CategorizedAdapt
private final List<T> mSelectedItems;
private final List<T> mDisabledItems;
private final List<T> mUnmovedItems;
final private List<T> mExceptions = new ArrayList<>();
private final List<T> mExceptions = new ArrayList<>();
private final IViewHolderBinder mBinder;
// Min and max counts
@@ -50,7 +50,8 @@ public class CategorizedAdapter<T> extends RecyclerView.Adapter<CategorizedAdapt
this.mBinder = binder;
}
public void setExceptions(T... exceptions) {
@SafeVarargs
public final void setExceptions(T... exceptions) {
mExceptions.clear();
mExceptions.addAll(Arrays.asList(exceptions));
}
@@ -186,11 +187,16 @@ public class CategorizedAdapter<T> extends RecyclerView.Adapter<CategorizedAdapt
&& mSelectedItems.size() == mMinSelectedItems))
return false;
if (getItemViewType(toPosition) == CATEGORY_TITLE) {
if (mExceptions.size() > 0) {
if (!mExceptions.isEmpty()) {
boolean except = false;
int q = 0;
for (var ex : mExceptions)
if (mSelectedItems.contains(ex)) ++q;
if (q == 1) return false;
for (var ex : mExceptions) {
var i = mSelectedItems.indexOf(ex);
if (i == -1) continue;
if (i + 1 == fromPosition) except = true;
++q;
}
if (except && q == 1) return false;
}
mDisabledItems.add(0, mSelectedItems.remove(fromPosition - 1));
} else Collections.swap(mSelectedItems, fromPosition - 1, toPosition - 1);
@@ -218,7 +224,6 @@ public class CategorizedAdapter<T> extends RecyclerView.Adapter<CategorizedAdapt
}
public static class CategorizedViewHolder extends RecyclerView.ViewHolder {
private final LinearLayout mMovingItemContainer;
private final ImageView mIcon;
private final TextView mName;
@@ -18,7 +18,6 @@ import ru.vtosters.hooks.other.ThemesUtils;
import ru.vtosters.lite.utils.AndroidUtils;
public class MessagesPreviewAdapter extends RecyclerView.Adapter<MessagesPreviewAdapter.MessagePreviewViewHolder> {
private final String[] mMessages;
public MessagesPreviewAdapter(String... messages) {
@@ -35,9 +34,9 @@ public class MessagesPreviewAdapter extends RecyclerView.Adapter<MessagesPreview
public MessagePreviewViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
Context context = viewGroup.getContext();
final var inflater = LayoutInflater.from(context);
var inflater = LayoutInflater.from(context);
final var bubbleFluidLayout = (BubbleFluidLayout) inflater.inflate(R.layout.vkim_msg_list_item_msg_from_user, viewGroup, false);
var bubbleFluidLayout = (BubbleFluidLayout) inflater.inflate(R.layout.vkim_msg_list_item_msg_from_user, viewGroup, false);
bubbleFluidLayout.setPadding(0, AndroidUtils.dp2px(4), 0, 0);
bubbleFluidLayout.setGravity(viewType);
@@ -47,7 +46,7 @@ public class MessagesPreviewAdapter extends RecyclerView.Adapter<MessagesPreview
bubbleFluidLayout.findViewById(R.id.status).setVisibility(View.GONE);
bubbleFluidLayout.findViewById(R.id.status_space).setVisibility(View.GONE);
final var messageBubbleView = (MsgBubbleView) bubbleFluidLayout.findViewById(R.id.bubble);
var messageBubbleView = (MsgBubbleView) bubbleFluidLayout.findViewById(R.id.bubble);
messageBubbleView.setContentPaddingLeft(AndroidUtils.dp2px(10));
messageBubbleView.setContentPaddingTop(AndroidUtils.dp2px(4));
messageBubbleView.setContentPaddingRight(AndroidUtils.dp2px(4));
@@ -59,10 +58,10 @@ public class MessagesPreviewAdapter extends RecyclerView.Adapter<MessagesPreview
}
bubbleFluidLayout.setLayoutDirection(viewType);
final var msgTextView = inflater.inflate(R.layout.vkim_msg_part_text, viewGroup, false);
var msgTextView = inflater.inflate(R.layout.vkim_msg_part_text, viewGroup, false);
msgTextView.setId(R.id.msg_text);
final var msgBubbleView = (MsgBubbleView) bubbleFluidLayout.findViewById(R.id.bubble);
var msgBubbleView = (MsgBubbleView) bubbleFluidLayout.findViewById(R.id.bubble);
msgBubbleView.setContentView(msgTextView);
return new MessagePreviewViewHolder(bubbleFluidLayout);
@@ -17,8 +17,8 @@ public class DisableBattery {
public static void alert(Activity activity) {
if (!(OEMDetector.isOEM() && Build.VERSION.SDK_INT >= 23 && Preferences.getBoolValue("showDoze", true)))
return;
final String packName = activity.getPackageName();
final PowerManager manager = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
String packName = activity.getPackageName();
PowerManager manager = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
if (manager.isIgnoringBatteryOptimizations(packName)) return;
new VkAlertDialog.Builder(activity)
.setTitle(R.string.batteryissuetitle)
@@ -1,5 +1,6 @@
package ru.vtosters.lite.ui.dialogs;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.view.View;
import android.widget.LinearLayout;
@@ -41,6 +42,7 @@ public class OTADialog extends ModalBottomSheetWrapper<OTADialog> implements OTA
});
}
@SuppressLint("SetTextI18n")
private View makeUpdateInfoView(String changelog) {
LinearLayout container = new LinearLayout(mActivity);
TextView changelogView = new TextView(mActivity);
@@ -37,16 +37,16 @@ public class AlphaView extends SliderViewBase implements ColorObserver {
@Override
protected Bitmap makeBitmap(int w, int h) {
final boolean isWide = w > h;
final int n = Math.max(w, h);
boolean isWide = w > h;
int n = Math.max(w, h);
int color = observableColor.getColor();
int[] colors = new int[n];
for (int i = 0; i < n; ++i) {
float alpha = isWide ? (float) i / n : 1 - (float) i / n;
colors[i] = color & 0xffffff | (int) (alpha * 0xff) << 24;
}
final int bmpWidth = isWide ? w : 1;
final int bmpHeight = isWide ? 1 : h;
int bmpWidth = isWide ? w : 1;
int bmpHeight = isWide ? 1 : h;
return Bitmap.createBitmap(colors, bmpWidth, bmpHeight, Bitmap.Config.ARGB_8888);
}
@@ -18,13 +18,12 @@ class HexEdit {
new HexFilter()
};
public static void setUpListeners(final EditText hexEdit, final ObservableColor observableColor) {
public static void setUpListeners(EditText hexEdit, ObservableColor observableColor) {
class MultiObserver implements ColorObserver, TextWatcher {
@Override
public void updateColor(ObservableColor observableColor) {
final String colorString = formatColor(observableColor.getColor());
String colorString = formatColor(observableColor.getColor());
// Prevent onTextChanged getting called when we update text programmatically
hexEdit.removeTextChangedListener(this);
hexEdit.setText(colorString);
@@ -57,7 +56,7 @@ class HexEdit {
}
}
final MultiObserver multiObserver = new MultiObserver();
MultiObserver multiObserver = new MultiObserver();
hexEdit.addTextChangedListener(multiObserver);
observableColor.addObserver(multiObserver);
setShowAlphaDigits(hexEdit, true);
@@ -71,14 +70,13 @@ class HexEdit {
}
}
public static void setShowAlphaDigits(final EditText hexEdit, boolean showAlphaDigits) {
public static void setShowAlphaDigits(EditText hexEdit, boolean showAlphaDigits) {
hexEdit.setFilters(showAlphaDigits ? withAlphaDigits : withoutAlphaDigits);
hexEdit.setText(hexEdit.getText()); // trigger a reformat of text
}
private static class ColorPasteLengthFilter implements InputFilter {
private static final int MAX_LENGTH = 6;
private static final int PASTED_LEN = 8;
private final InputFilter sixDigitFilter = new InputFilter.LengthFilter(MAX_LENGTH);
@@ -86,8 +84,8 @@ class HexEdit {
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
// If 8 digits have been pasted, replacing all source, trim alpha digits.
// Otherwise standard LengthFilter behavior.
final int srcLength = end - start;
final int dstSelLength = dend - dstart;
int srcLength = end - start;
int dstSelLength = dend - dstart;
if (srcLength == PASTED_LEN && dstSelLength == dest.length()) {
// Discard alpha digits:
return source.subSequence(PASTED_LEN - MAX_LENGTH, PASTED_LEN);
@@ -98,7 +96,6 @@ class HexEdit {
}
private static class HexFilter implements InputFilter {
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
boolean state = true;
@@ -57,9 +57,9 @@ public class HueSatView extends SquareView implements ColorObserver {
float[] hsv = new float[]{0f, 0f, 1f};
for (int y = 0; y < radiusPx; ++y) {
for (int x = 0; x < radiusPx; ++x) {
final int i = x + y * radiusPx;
final float sat = satForPos(x, y, radiusPx);
final float arcBleed = 2f / radiusPx; // extend curved edge pixels just outside clip area.
int i = x + y * radiusPx;
float sat = satForPos(x, y, radiusPx);
float arcBleed = 2f / radiusPx; // extend curved edge pixels just outside clip area.
if (sat <= 1 + arcBleed) {
hsv[0] = hueForPos(x, y, radiusPx);
hsv[1] = sat;
@@ -71,35 +71,35 @@ public class HueSatView extends SquareView implements ColorObserver {
}
private static float hueForPos(float x, float y, float radiusPx) {
final double r = radiusPx - 1; // gives values 0...1 inclusive
final double dx = (r - x) / r;
final double dy = (r - y) / r;
final double angle = Math.atan2(dy, dx);
final double hue = 360 * angle / (Math.PI / 2);
double r = radiusPx - 1; // gives values 0...1 inclusive
double dx = (r - x) / r;
double dy = (r - y) / r;
double angle = Math.atan2(dy, dx);
double hue = 360 * angle / (Math.PI / 2);
return (float) hue;
}
private static float satForPos(float x, float y, float radiusPx) {
final double r = radiusPx - 1; // gives values 0...1 inclusive
final double dx = (r - x) / r;
final double dy = (r - y) / r;
final double sat = dx * dx + dy * dy; // leave it squared -- exaggerates pale colors
double r = radiusPx - 1; // gives values 0...1 inclusive
double dx = (r - x) / r;
double dy = (r - y) / r;
double sat = dx * dx + dy * dy; // leave it squared -- exaggerates pale colors
return (float) sat;
}
private static void setPointer(PointF pointer, float hue, float sat, float radiusPx) {
final float r = radiusPx - 1; // for values 0...1 inclusive
final double distance = r * Math.sqrt(sat);
final double angle = hue / 360 * Math.PI / 2;
final double dx = distance * Math.cos(angle);
final double dy = distance * Math.sin(angle);
float r = radiusPx - 1; // for values 0...1 inclusive
double distance = r * Math.sqrt(sat);
double angle = hue / 360 * Math.PI / 2;
double dx = distance * Math.cos(angle);
double dy = distance * Math.sin(angle);
pointer.set(r - (float) dx, r - (float) dy);
}
private int optimalBitmapSize() {
final int scale = 2;
final int maxBitmapSize = 128;
final DisplayMetrics dm = getResources().getDisplayMetrics();
int scale = 2;
int maxBitmapSize = 128;
DisplayMetrics dm = getResources().getDisplayMetrics();
return Math.min(maxBitmapSize, Math.min(dm.widthPixels, dm.heightPixels) / scale);
}
@@ -159,9 +159,9 @@ public class HueSatView extends SquareView implements ColorObserver {
private boolean clamp(PointF pointer, float x, float y, boolean rejectOutside) {
x = Math.min(x, w);
y = Math.min(y, h);
final float dx = w - x;
final float dy = h - y;
final float r = (float) Math.sqrt(dx * dx + dy * dy);
float dx = w - x;
float dy = h - y;
float r = (float) Math.sqrt(dx * dx + dy * dy);
boolean outside = r > w;
if (!outside || !rejectOutside) {
if (outside) {
@@ -6,7 +6,6 @@ import android.view.MotionEvent;
import android.view.View;
public abstract class SliderViewBase extends View {
private final Paint borderPaint;
private final Paint checkerPaint;
private final Rect viewRect = new Rect();
@@ -18,10 +18,10 @@ class SquareView extends View {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Constrain to square
final int w = MeasureSpec.getSize(widthMeasureSpec);
final int h = MeasureSpec.getSize(heightMeasureSpec);
final int modeW = MeasureSpec.getMode(widthMeasureSpec);
final int modeH = MeasureSpec.getMode(heightMeasureSpec);
int w = MeasureSpec.getSize(widthMeasureSpec);
int h = MeasureSpec.getSize(heightMeasureSpec);
int modeW = MeasureSpec.getMode(widthMeasureSpec);
int modeH = MeasureSpec.getMode(heightMeasureSpec);
int size = minSizePx;
if (modeW == MeasureSpec.UNSPECIFIED) {
size = h;
@@ -8,7 +8,6 @@ import android.graphics.RectF;
import ru.vtosters.lite.utils.AndroidUtils;
public class SwatchView extends SquareView implements ColorObserver {
private final Paint borderPaint;
private final Path borderPath;
private final Paint checkerPaint;
@@ -46,14 +45,14 @@ public class SwatchView extends SquareView implements ColorObserver {
}
private static void cornerArc(Path path, float cx, float cy, float r, float startAngle, float sweepAngle) {
final RectF ovalRect = new RectF(-r, -r, r, r);
RectF ovalRect = new RectF(-r, -r, r, r);
ovalRect.offset(cx, cy);
path.arcTo(ovalRect, startAngle, sweepAngle);
}
private static void mainArc(Path path, float viewSize, float margin, float startAngle, float sweepAngle) {
float r = viewSize + margin;
final RectF ovalRect = new RectF(-r, -r, r, r);
RectF ovalRect = new RectF(-r, -r, r, r);
ovalRect.offset(viewSize, viewSize);
path.arcTo(ovalRect, startAngle, sweepAngle);
}
@@ -77,23 +76,23 @@ public class SwatchView extends SquareView implements ColorObserver {
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// We expect to be stacked behind a square HueSatView and fill the top left corner.
final float inset = borderPaint.getStrokeWidth() / 2;
final float r = Math.min(w, h);
float inset = borderPaint.getStrokeWidth() / 2;
float r = Math.min(w, h);
// Trim the corners of the swatch is where it is radialMarginPx thick.
// find how long the outeredges are:
final float margin = radialMarginPx;
final float diagonal = r + 2 * margin;
final float opp = (float) Math.sqrt(diagonal * diagonal - r * r);
final float edgeLen = r - opp;
float margin = radialMarginPx;
float diagonal = r + 2 * margin;
float opp = (float) Math.sqrt(diagonal * diagonal - r * r);
float edgeLen = r - opp;
// Arc angles for drawing CCW
final float outerAngle = (float) Math.toDegrees(Math.atan2(opp, r));
final float startAngle = 270 - outerAngle;
float outerAngle = (float) Math.toDegrees(Math.atan2(opp, r));
float startAngle = 270 - outerAngle;
// Sweep angle for each half of the swatch:
final float sweepAngle = outerAngle - 45;
float sweepAngle = outerAngle - 45;
// Sweep angle for the smooth corners:
final float cornerSweepAngle = 90 - outerAngle;
float cornerSweepAngle = 90 - outerAngle;
// Outer border:
beginBorder(borderPath, inset, edgeLen, margin, cornerSweepAngle);
@@ -5,7 +5,6 @@ import android.graphics.Bitmap;
import android.graphics.Color;
public class ValueView extends SliderViewBase implements ColorObserver {
private ObservableColor observableColor = new ObservableColor(0);
public ValueView(Context context) {
@@ -37,8 +36,8 @@ public class ValueView extends SliderViewBase implements ColorObserver {
}
protected Bitmap makeBitmap(int w, int h) {
final boolean isWide = w > h;
final int n = Math.max(w, h);
boolean isWide = w > h;
int n = Math.max(w, h);
int[] colors = new int[n];
float[] hsv = new float[]{0, 0, 0};
@@ -48,8 +47,8 @@ public class ValueView extends SliderViewBase implements ColorObserver {
hsv[2] = isWide ? (float) i / n : 1 - (float) i / n;
colors[i] = Color.HSVToColor(hsv);
}
final int bmpWidth = isWide ? w : 1;
final int bmpHeight = isWide ? 1 : h;
int bmpWidth = isWide ? w : 1;
int bmpHeight = isWide ? 1 : h;
return Bitmap.createBitmap(colors, bmpWidth, bmpHeight, Bitmap.Config.ARGB_8888);
}
@@ -46,7 +46,7 @@ public class AndroidUtils {
@NonNull
public static Context getGlobalContext() {
try {
final Method getInitialApplicationMtd = ReflectionUtils.findMethod(Class.forName("android.app.AppGlobals"), "getInitialApplication");
Method getInitialApplicationMtd = ReflectionUtils.findMethod(Class.forName("android.app.AppGlobals"), "getInitialApplication");
return (Context) getInitialApplicationMtd.invoke(null);
} catch (Exception e) {
Log.d("GlobalContext", "Error while fetching context via refl");
@@ -186,8 +186,8 @@ public class AndroidUtils {
}
private static String getRandomString(int sizeOfRandomString) {
final Random random = new Random();
final StringBuilder sb = new StringBuilder(sizeOfRandomString);
Random random = new Random();
StringBuilder sb = new StringBuilder(sizeOfRandomString);
for (int i = 0; i < sizeOfRandomString; ++i)
sb.append(ALLOWED_CHARACTERS.charAt(random.nextInt(ALLOWED_CHARACTERS.length())));
return sb.toString();
@@ -221,7 +221,6 @@ public class AndroidUtils {
long lastUpdateTime = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).lastUpdateTime;
return firstInstallTime == lastUpdateTime;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return true;
}
}
@@ -26,7 +26,7 @@ public class CrashReporter {
}
public static void init(Activity activity) {
final var defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
var defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler((thread, th) -> CrashReporter.start(defaultUncaughtExceptionHandler, thread, th, activity));
}
@@ -76,9 +76,8 @@ public class CrashReporter {
}
private static boolean isFoxbinInstalled() {
var pm = getGlobalContext().getPackageManager();
try {
pm.getPackageInfo("com.f0x1d.dogbin", 0);
getGlobalContext().getPackageManager().getPackageInfo("com.f0x1d.dogbin", 0);
return true;
} catch (Exception e) {
return false;
@@ -16,7 +16,7 @@ import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
public class IOUtils {
public static final int BUFFER_SIZE = 8192;
public static int BUFFER_SIZE = 8192;
public static byte[] decodeStream(InputStream encIs, byte[] aesKey)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IOException {
@@ -51,11 +51,11 @@ public class IOUtils {
return new String(readFully(is), StandardCharsets.UTF_8);
}
public static byte[] readFully(final InputStream is)
public static byte[] readFully(InputStream is)
throws IOException {
final var bos = new ByteArrayOutputStream();
var bos = new ByteArrayOutputStream();
try (bos) {
final byte[] buff = new byte[BUFFER_SIZE];
byte[] buff = new byte[BUFFER_SIZE];
int len;
while ((len = is.read(buff)) > 0)
bos.write(buff, 0, len);
@@ -63,7 +63,7 @@ public class IOUtils {
}
}
public static byte[] readFully(final File in)
public static byte[] readFully(File in)
throws IOException {
return readFully(new FileInputStream(in));
}
@@ -80,25 +80,25 @@ public class IOUtils {
fos.close();
}
public static void copy(final InputStream is, final OutputStream os)
public static void copy(InputStream is, OutputStream os)
throws IOException {
final byte[] buff = new byte[BUFFER_SIZE];
byte[] buff = new byte[BUFFER_SIZE];
int len;
while ((len = is.read(buff)) > 0)
os.write(buff, 0, len);
}
public static void copy(final byte[] buffer, final File out)
public static void copy(byte[] buffer, File out)
throws IOException {
copy(new ByteArrayInputStream(buffer), new FileOutputStream(out));
}
public static void copy(final InputStream is, final File out)
public static void copy(InputStream is, File out)
throws IOException {
copy(is, new FileOutputStream(out));
}
public static void copy(final File in, final File out)
public static void copy(File in, File out)
throws IOException {
copy(new FileInputStream(in), new FileOutputStream(out));
}
@@ -119,7 +119,7 @@ public class IOUtils {
}
public static long getDirSize(File dir) {
final var arr = dir.listFiles();
var arr = dir.listFiles();
if (arr == null || arr.length == 0)
return 0;
@@ -242,13 +242,13 @@ public class NewsFeedFiltersUtils {
return false;
}
if (checkCopyright(post) && !isWhitelistedFilters(post)) {
if (checkCopyright(post)) {
if (dev())
Log.d("NewsfeedAdBlockV2", "Removed post " + post.optInt("post_id") + " from discover, Reason: copyright filters");
return false;
}
if (checkCaption(post) && !isWhitelistedFilters(post)) {
if (checkCaption(post)) {
if (dev())
Log.d("NewsfeedAdBlockV2", "Removed post " + post.optInt("post_id") + " from discover, Reason: caption filters");
return false;
@@ -448,13 +448,13 @@ public class NewsFeedFiltersUtils {
continue;
}
if (checkCopyright(list) && !isWhitelistedFilters(list)) {
if (checkCopyright(list)) {
if (dev())
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: copyright filters");
continue;
}
if (checkCaption(list) && !isWhitelistedFilters(list)) {
if (checkCaption(list)) {
if (dev())
Log.d("NewsfeedAdBlockV2", "Removed post " + list.optInt("post_id") + " from feed, Reason: caption filters");
continue;
@@ -17,6 +17,9 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import static android.os.Environment.DIRECTORY_DOWNLOADS;
import static android.os.Environment.getExternalStoragePublicDirectory;
public class VKAccountDB {
private static SQLiteOpenHelper getDatabase() {
return new UsersDbHelper(AndroidUtils.getGlobalContext());
@@ -70,11 +73,11 @@ public class VKAccountDB {
var db = getDatabase().getReadableDatabase();
var dateFormat = new SimpleDateFormat("yyyy-MM-dd.HH-mm-ss", Locale.getDefault());
var file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/VTLBackups/saved_accounts_" + dateFormat.format(new Date()) + ".vtl");
var dir = new File(getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS), "/VTLBackups/");
var file = new File(dir, "saved_accounts_" + dateFormat.format(new Date()) + ".vtl");
InputStream inputStream;
try {
inputStream = new FileInputStream(db.getPath());
try (InputStream inputStream = new FileInputStream(db.getPath())){
dir.mkdirs();
FileOutputStream outputStream = new FileOutputStream(file);
byte[] buff = new byte[1024];
@@ -86,7 +89,6 @@ public class VKAccountDB {
AndroidUtils.sendToast(AndroidUtils.getString("accounts_saved_by_path") + " " + file.getPath());
} catch (IOException e) {
e.printStackTrace();
AndroidUtils.sendToast(AndroidUtils.getString("error_saving_file"));
}
}
@@ -222,41 +222,41 @@
.line 14
:cond_0
new-instance v0, Lcom/vk/api/audio/AudioSendStartEvent;
# new-instance v0, Lcom/vk/api/audio/AudioSendStartEvent;
invoke-virtual {p1}, Lcom/vk/dto/music/MusicTrack;->y1()Ljava/lang/String;
# invoke-virtual {p1}, Lcom/vk/dto/music/MusicTrack;->y1()Ljava/lang/String;
move-result-object p1
# move-result-object p1
sget-object v2, Lcom/vk/api/base/ApiConfig;->d:Lcom/vk/api/base/ApiConfig$a;
# sget-object v2, Lcom/vk/api/base/ApiConfig;->d:Lcom/vk/api/base/ApiConfig$a;
invoke-interface {v2}, Lcom/vk/api/base/ApiConfig$a;->O1()Ljava/lang/String;
# invoke-interface {v2}, Lcom/vk/api/base/ApiConfig$a;->O1()Ljava/lang/String;
move-result-object v2
# move-result-object v2
invoke-direct {v0, p1, v2}, Lcom/vk/api/audio/AudioSendStartEvent;-><init>(Ljava/lang/String;Ljava/lang/String;)V
# invoke-direct {v0, p1, v2}, Lcom/vk/api/audio/AudioSendStartEvent;-><init>(Ljava/lang/String;Ljava/lang/String;)V
const/4 p1, 0x0
# const/4 p1, 0x0
.line 15
invoke-static {v0, p1, v1, p1}, Lcom/vk/api/base/ApiRequest;->d(Lcom/vk/api/base/ApiRequest;Lcom/vk/api/base/ApiThreadHolder;ILjava/lang/Object;)Lio/reactivex/Observable;
# .line 15
# invoke-static {v0, p1, v1, p1}, Lcom/vk/api/base/ApiRequest;->d(Lcom/vk/api/base/ApiRequest;Lcom/vk/api/base/ApiThreadHolder;ILjava/lang/Object;)Lio/reactivex/Observable;
move-result-object p1
# move-result-object p1
.line 16
new-instance v0, Lcom/vk/music/notifications/restriction/MusicRestrictionModelImpl$d;
# .line 16
# new-instance v0, Lcom/vk/music/notifications/restriction/MusicRestrictionModelImpl$d;
invoke-direct {v0, p0}, Lcom/vk/music/notifications/restriction/MusicRestrictionModelImpl$d;-><init>(Lcom/vk/music/notifications/restriction/MusicRestrictionModelImpl;)V
# invoke-direct {v0, p0}, Lcom/vk/music/notifications/restriction/MusicRestrictionModelImpl$d;-><init>(Lcom/vk/music/notifications/restriction/MusicRestrictionModelImpl;)V
.line 17
sget-object v1, Lcom/vk/music/notifications/restriction/MusicRestrictionModelImpl$e;->a:Lcom/vk/music/notifications/restriction/MusicRestrictionModelImpl$e;
# .line 17
# sget-object v1, Lcom/vk/music/notifications/restriction/MusicRestrictionModelImpl$e;->a:Lcom/vk/music/notifications/restriction/MusicRestrictionModelImpl$e;
.line 18
invoke-virtual {p1, v0, v1}, Lio/reactivex/Observable;->a(Lio/reactivex/functions/Consumer;Lio/reactivex/functions/Consumer;)Lio/reactivex/disposables/Disposable;
# .line 18
# invoke-virtual {p1, v0, v1}, Lio/reactivex/Observable;->a(Lio/reactivex/functions/Consumer;Lio/reactivex/functions/Consumer;)Lio/reactivex/disposables/Disposable;
move-result-object p1
# move-result-object p1
iput-object p1, p0, Lcom/vk/music/notifications/restriction/MusicRestrictionModelImpl;->a:Lio/reactivex/disposables/Disposable;
# iput-object p1, p0, Lcom/vk/music/notifications/restriction/MusicRestrictionModelImpl;->a:Lio/reactivex/disposables/Disposable;
return-void
.end method