diff --git a/Bcore/src/main/cpp/Utils/AntiDetection.cpp b/Bcore/src/main/cpp/Utils/AntiDetection.cpp index 8065b2b..10b2bb7 100644 --- a/Bcore/src/main/cpp/Utils/AntiDetection.cpp +++ b/Bcore/src/main/cpp/Utils/AntiDetection.cpp @@ -53,7 +53,7 @@ static const char* blocked_files[] = { "/data/data/com.lbe.parallel", "/data/data/com.dual.dualspace", "/data/data/com.ludashi.superboost", - "/data/data/top.niunaijun.blackboxa", + "/data/data/com.qm4rs.fridabox", "/blackbox", "/virtual", diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/BlackBoxCore.java b/Bcore/src/main/java/top/niunaijun/blackbox/BlackBoxCore.java index 766bfae..8a5ec11 100644 --- a/Bcore/src/main/java/top/niunaijun/blackbox/BlackBoxCore.java +++ b/Bcore/src/main/java/top/niunaijun/blackbox/BlackBoxCore.java @@ -1138,7 +1138,7 @@ public class BlackBoxCore extends ClientConfiguration { try { if (packageName.equals(getHostPkg())) { - return new InstallResult().installError("Cannot clone BlackBox app from within BlackBox. This would create infinite recursion and is not allowed for security reasons."); + return new InstallResult().installError("Cannot clone FridaBox from inside its own workspace. This would create infinite recursion and is not allowed for security reasons."); } PackageInfo packageInfo = getPackageManager().getPackageInfo(packageName, 0); @@ -1156,7 +1156,7 @@ public class BlackBoxCore extends ClientConfiguration { if (packageInfo != null) { String packageName = packageInfo.packageName; if (packageName.equals(getHostPkg())) { - return new InstallResult().installError("Cannot clone BlackBox app from within BlackBox. This would create infinite recursion and is not allowed for security reasons."); + return new InstallResult().installError("Cannot clone FridaBox from inside its own workspace. This would create infinite recursion and is not allowed for security reasons."); } } } catch (Exception e) { @@ -2126,7 +2126,7 @@ public class BlackBoxCore extends ClientConfiguration { } builder.setSmallIcon(android.R.drawable.stat_notify_error) - .setContentTitle("BlackBox Log Upload Failed") + .setContentTitle("FridaBox Log Upload Failed") .setContentText(error) .setAutoCancel(true); @@ -2157,7 +2157,7 @@ public class BlackBoxCore extends ClientConfiguration { } builder.setSmallIcon(android.R.drawable.stat_sys_upload_done) - .setContentTitle("BlackBox Log Upload") + .setContentTitle("FridaBox Log Upload") .setContentText("Logs sent successfully") .setAutoCancel(true); diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BPackageManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BPackageManager.java index bfeaa90..e0c8782 100644 --- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BPackageManager.java +++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BPackageManager.java @@ -506,8 +506,8 @@ public class BPackageManager extends BlackManager { String packageName = packageInfo.packageName; String hostPackageName = BlackBoxCore.getHostPkg(); if (packageName.equals(hostPackageName)) { - Log.w(TAG, "Attempt to install BlackBox app detected and blocked: " + packageName); - return new InstallResult().installError("Cannot clone BlackBox app from within BlackBox. This would create infinite recursion and is not allowed for security reasons."); + Log.w(TAG, "Attempt to install the FridaBox host app was blocked: " + packageName); + return new InstallResult().installError("Cannot clone FridaBox from inside its own workspace. This would create infinite recursion and is not allowed for security reasons."); } } } catch (Exception e) { diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityManagerProxy.java index 4f571d1..636fbc1 100644 --- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityManagerProxy.java +++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityManagerProxy.java @@ -768,8 +768,8 @@ public class IActivityManagerProxy extends ClassInvocationStub { public static class getCurrentUser extends MethodHook { @Override protected Object hook(Object who, Method method, Object[] args) throws Throwable { - Object blackBox = BRUserInfo.get()._new(BActivityThread.getUserId(), "BlackBox", BRUserInfo.get().FLAG_PRIMARY()); - return blackBox; + Object fridaBox = BRUserInfo.get()._new(BActivityThread.getUserId(), "FridaBox", BRUserInfo.get().FLAG_PRIMARY()); + return fridaBox; } } diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDevicePolicyManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDevicePolicyManagerProxy.java index 6489560..9d173a6 100644 --- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDevicePolicyManagerProxy.java +++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDevicePolicyManagerProxy.java @@ -57,7 +57,7 @@ public class IDevicePolicyManagerProxy extends BinderInvocationStub { @Override protected Object hook(Object who, Method method, Object[] args) throws Throwable { - return "BlackBox"; + return "FridaBox"; } } @@ -66,7 +66,7 @@ public class IDevicePolicyManagerProxy extends BinderInvocationStub { @Override protected Object hook(Object who, Method method, Object[] args) throws Throwable { - return "BlackBox"; + return "FridaBox"; } } diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IUserManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IUserManagerProxy.java index ccb30dd..55747c0 100644 --- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IUserManagerProxy.java +++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IUserManagerProxy.java @@ -48,8 +48,8 @@ public class IUserManagerProxy extends BinderInvocationStub { public static class GetProfileParent extends MethodHook { @Override protected Object hook(Object who, Method method, Object[] args) throws Throwable { - Object blackBox = BRUserInfo.get()._new(BActivityThread.getUserId(), "BlackBox", BRUserInfo.get().FLAG_PRIMARY()); - return blackBox; + Object fridaBox = BRUserInfo.get()._new(BActivityThread.getUserId(), "FridaBox", BRUserInfo.get().FLAG_PRIMARY()); + return fridaBox; } } diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWifiManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWifiManagerProxy.java index 2f1f81d..2b4ccbc 100644 --- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWifiManagerProxy.java +++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWifiManagerProxy.java @@ -45,7 +45,7 @@ public class IWifiManagerProxy extends BinderInvocationStub { WifiInfo wifiInfo = (WifiInfo) method.invoke(who, args); BRWifiInfo.get(wifiInfo)._set_mBSSID("ac:62:5a:82:65:c4"); BRWifiInfo.get(wifiInfo)._set_mMacAddress("ac:62:5a:82:65:c4"); - BRWifiInfo.get(wifiInfo)._set_mWifiSsid(BRWifiSsid.get().createFromAsciiEncoded("BlackBox_Wifi")); + BRWifiInfo.get(wifiInfo)._set_mWifiSsid(BRWifiSsid.get().createFromAsciiEncoded("FridaBox_Wifi")); return wifiInfo; } diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WebViewProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WebViewProxy.java index e356e0d..9dd88f0 100644 --- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WebViewProxy.java +++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WebViewProxy.java @@ -139,9 +139,7 @@ public class WebViewProxy extends ClassInvocationStub { String userAgent = settings.getUserAgentString(); - if (userAgent != null && !userAgent.contains("BlackBox")) { - settings.setUserAgentString(userAgent + " BlackBox"); - } + // Keep the guest's original user-agent; host branding must not leak into it. try { diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyVpnService.java b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyVpnService.java index 0a39e61..17f13b0 100644 --- a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyVpnService.java +++ b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyVpnService.java @@ -15,7 +15,7 @@ import top.niunaijun.blackbox.utils.Slog; public class ProxyVpnService extends VpnService { private static final String TAG = "ProxyVpnService"; private static final int NOTIFICATION_ID = 1001; - private static final String CHANNEL_ID = "BlackBoxVPN"; + private static final String CHANNEL_ID = "FridaBoxVPN"; private ParcelFileDescriptor mVpnInterface = null; private boolean mIsEstablished = false; @@ -74,10 +74,10 @@ public class ProxyVpnService extends VpnService { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( CHANNEL_ID, - "BlackBox VPN Service", + "FridaBox VPN Service", NotificationManager.IMPORTANCE_LOW ); - channel.setDescription("VPN service for BlackBox network access"); + channel.setDescription("VPN service for FridaBox network access"); channel.setShowBadge(false); NotificationManager notificationManager = getSystemService(NotificationManager.class); @@ -98,7 +98,7 @@ public class ProxyVpnService extends VpnService { } return builder - .setContentTitle("BlackBox VPN Active") + .setContentTitle("FridaBox VPN Active") .setContentText("Managing network access for sandboxed apps") .setSmallIcon(android.R.drawable.ic_dialog_info) .setOngoing(true) @@ -124,7 +124,7 @@ public class ProxyVpnService extends VpnService { Builder builder = new Builder(); - builder.setSession("BlackBox VPN"); + builder.setSession("FridaBox VPN"); builder.addAddress("10.0.0.2", 32); @@ -140,7 +140,7 @@ public class ProxyVpnService extends VpnService { builder.addAllowedApplication(getPackageName()); - builder.setSession("BlackBox Internet Access"); + builder.setSession("FridaBox Internet Access"); Slog.d(TAG, "VPN builder configured, establishing interface..."); @@ -210,7 +210,7 @@ public class ProxyVpnService extends VpnService { Slog.e(TAG, "Error in network monitoring: " + e.getMessage()); } } - }, "BlackBoxNetworkHandler"); + }, "FridaBoxNetworkHandler"); mNetworkThread.start(); Slog.d(TAG, "Network handling thread started"); diff --git a/Docs.md b/Docs.md deleted file mode 100644 index b7094b0..0000000 --- a/Docs.md +++ /dev/null @@ -1,522 +0,0 @@ -# BlackBox Virtual Environment - Complete User Guide - -## Table of Contents -1. [Overview](#overview) -2. [Installation & Setup](#installation--setup) -3. [App Management](#app-management) -4. [WebView & Browser Support](#webview--browser-support) -5. [Google Services Integration](#google-services-integration) -6. [Background Job Management](#background-job-management) -7. [Troubleshooting](#troubleshooting) -8. [Advanced Features](#advanced-features) -9. [API Reference](#api-reference) -10. [Frequently Asked Questions](#frequently-asked-questions) - ---- - -## Overview - -BlackBox is a comprehensive Android virtualization solution that creates isolated environments for running apps. The latest version includes significant improvements for: - -- **App Installation & Management**: Robust app installation with cloning prevention -- **WebView Support**: Complete WebView compatibility for browsers and web apps -- **Google Services**: Enhanced Google account and GMS integration -- **Background Jobs**: WorkManager and JobScheduler compatibility -- **UID Management**: Smart UID spoofing for system compatibility -- **Crash Prevention**: Comprehensive error handling and recovery - ---- - -## Installation & Setup - -### Prerequisites -- Android 8.0+ (API 26+) -- Root access (recommended for full functionality) -- At least 2GB free storage space -- Internet connection for initial setup - -### Basic Installation -1. **Download BlackBox APK** from the official source -2. **Install the APK** using your preferred method -3. **Grant Permissions** when prompted: - - Storage access - - System overlay (for floating features) - - Location (for GPS spoofing) - - Notification access (Android 12+) - -### Initial Configuration -```bash -# First launch will create virtual environment -# Wait for initialization to complete -# Check logs for any setup issues -``` - ---- - -## App Management - -### Installing Apps - -#### Method 1: APK File Installation -```java -// Using BlackBoxCore API -BlackBoxCore.get().installPackageAsUser(apkFile, userId); - -// Example with error handling -try { - InstallResult result = BlackBoxCore.get().installPackageAsUser(apkFile, 0); - if (result.isSuccess()) { - Log.d("BlackBox", "App installed successfully: " + result.getPackageName()); - } else { - Log.e("BlackBox", "Installation failed: " + result.getErrorMessage()); - } -} catch (Exception e) { - Log.e("BlackBox", "Installation error", e); -} -``` - -#### Method 2: Package Name Installation -```java -// Install from existing package -BlackBoxCore.get().installPackageAsUser("com.example.app", userId); - -// Check if package exists first -if (BlackBoxCore.getPackageManager().getPackageInfo("com.example.app", 0) != null) { - BlackBoxCore.get().installPackageAsUser("com.example.app", userId); -} -``` - -#### Method 3: URI Installation -```java -// Install from content URI -Uri apkUri = Uri.parse("content://com.example.provider/app.apk"); -BlackBoxCore.get().installPackageAsUser(apkUri, userId); -``` - -### App Removal - -#### Uninstall Virtual App -```java -// Remove app from virtual environment -BlackBoxCore.get().uninstallPackage(packageName, userId); - -// Force uninstall if needed -BlackBoxCore.get().uninstallPackage(packageName, userId, true); -``` - -#### Clean App Data -```java -// Clear app data without uninstalling -BlackBoxCore.get().clearAppData(packageName, userId); - -// Clear specific data types -BlackBoxCore.get().clearAppData(packageName, userId, "cache"); -BlackBoxCore.get().clearAppData(packageName, userId, "data"); -``` - -### App Management Utilities - -#### List Installed Apps -```java -// Get all virtual apps -List virtualApps = BlackBoxCore.get().getInstalledApps(userId); - -// Get specific app info -AppInfo appInfo = BlackBoxCore.get().getAppInfo(packageName, userId); - -// Check if app is installed -boolean isInstalled = BlackBoxCore.get().isAppInstalled(packageName, userId); -``` - -#### App Configuration -```java -// Enable/disable app -BlackBoxCore.get().setAppEnabled(packageName, userId, true); - -// Set app permissions -BlackBoxCore.get().setAppPermission(packageName, permission, userId, true); - -// Configure app settings -BlackBoxCore.get().setAppSetting(packageName, setting, value, userId); -``` - ---- - -## WebView & Browser Support - -### WebView Configuration - -#### Automatic WebView Setup -The new WebView system automatically handles: -- **Unique Data Directories**: Each virtual app gets isolated WebView storage -- **Process Isolation**: WebView conflicts between apps are prevented -- **Data Persistence**: WebView data is preserved per app - -#### Manual WebView Configuration -```java -// Set custom WebView data directory -WebView.setDataDirectorySuffix("custom_suffix"); - -// Configure WebView settings -WebView webView = new WebView(context); -WebSettings settings = webView.getSettings(); -settings.setJavaScriptEnabled(true); -settings.setDomStorageEnabled(true); -settings.setDatabaseEnabled(true); -``` - -### Browser App Support - -#### Chrome/Firefox Compatibility -```java -// Browser apps automatically get: -// - Isolated WebView instances -// - Separate cookie storage -// - Independent cache directories -// - Process isolation -``` - -#### Web App Support -```java -// Progressive Web Apps (PWAs) work with: -// - Service worker isolation -// - Cache storage separation -// - Background sync support -``` - ---- - -## Google Services Integration - -### Google Account Management - -#### Automatic Account Handling -```java -// Google accounts are automatically managed: -// - Mock Google accounts for virtual environment -// - Authentication token handling -// - Account synchronization -``` - -#### Custom Account Configuration -```java -// Add custom Google accounts -AccountManager accountManager = AccountManager.get(context); -Account account = new Account("user@gmail.com", "com.google"); -accountManager.addAccountExplicitly(account, "password", null); - -// Configure account sync -ContentResolver.setSyncAutomatically(account, "com.google", true); -``` - -### Google Play Services - -#### GMS Compatibility -```java -// Google Play Services automatically: -// - Returns mock package info -// - Handles authentication requests -// - Provides fallback implementations -``` - -#### Custom GMS Configuration -```java -// Override GMS behavior if needed -GmsProxy.setCustomGmsInfo("com.example.gms", customInfo); - -// Configure GMS permissions -GmsProxy.setGmsPermission("com.example.gms", permission, true); -``` - ---- - -## Background Job Management - -### WorkManager Integration - -#### Automatic WorkManager Handling -```java -// WorkManager automatically: -// - Handles UID validation issues -// - Provides fallback implementations -// - Prevents crashes on job scheduling -``` - -#### Custom Work Configuration -```java -// Configure custom work -WorkManager workManager = WorkManager.getInstance(context); - -// Create work request -OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWorker.class) - .setInputData(inputData) - .build(); - -// Enqueue work -workManager.enqueue(workRequest); -``` - -### JobScheduler Compatibility - -#### Job Scheduling -```java -// Jobs are automatically handled with: -// - UID validation bypass -// - Fallback mechanisms -// - Error recovery -``` - -#### Custom Job Configuration -```java -// Create custom job -JobInfo.Builder builder = new JobInfo.Builder(jobId, componentName); -builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); -builder.setRequiresCharging(true); - -// Schedule job -JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); -scheduler.schedule(builder.build()); -``` - ---- - -## Advanced Features - -### UID Spoofing - -#### Automatic UID Management -```java -// UID spoofing automatically: -// - Detects UID validation issues -// - Selects appropriate UIDs for operations -// - Provides fallback UIDs when needed -``` - -#### Custom UID Configuration -```java -// Configure custom UID for specific operations -UIDSpoofingHelper.setCustomUID("operation", "package", customUID); - -// Override UID selection logic -UIDSpoofingHelper.setUIDStrategy("operation", customStrategy); -``` - -### Process Management - -#### Virtual Process Control -```java -// Control virtual processes -BlackBoxCore.get().startVirtualProcess(packageName, userId); -BlackBoxCore.get().stopVirtualProcess(packageName, userId); - -// Monitor process status -ProcessInfo processInfo = BlackBoxCore.get().getProcessInfo(packageName, userId); -``` - -#### Memory Management -```java -// Optimize memory usage -BlackBoxCore.get().optimizeMemory(userId); - -// Clear unused resources -BlackBoxCore.get().clearUnusedResources(userId); -``` - ---- - -## Troubleshooting - -### Common Issues - -#### App Installation Failures -```bash -# Check logs for installation errors -adb logcat | grep "BlackBox" - -# Common solutions: -# 1. Ensure sufficient storage space -# 2. Check APK file integrity -# 3. Verify package compatibility -# 4. Clear BlackBox cache -``` - -#### WebView Issues -```bash -# WebView troubleshooting: -# 1. Check WebView data directories -# 2. Verify WebView provider status -# 3. Clear WebView cache -# 4. Restart virtual environment -``` - -#### Google Services Problems -```bash -# GMS troubleshooting: -# 1. Check GMS proxy status -# 2. Verify account configuration -# 3. Clear GMS cache -# 4. Reinstall GMS components -``` - -### Debug Mode - -#### Enable Debug Logging -```java -// Enable comprehensive logging -BlackBoxCore.setDebugMode(true); - -// Set log level -Slog.setLogLevel(Slog.LEVEL_DEBUG); - -// Enable specific debug features -BlackBoxCore.enableDebugFeature("webview", true); -BlackBoxCore.enableDebugFeature("gms", true); -``` - -#### Log Analysis -```bash -# Filter BlackBox logs -adb logcat | grep "BlackBox\|WebView\|GmsProxy\|WorkManager" - -# Save logs to file -adb logcat > blackbox_logs.txt - -# Analyze specific components -adb logcat | grep "JobServiceStub\|WebViewProxy\|GoogleAccountManagerProxy" -``` - ---- - -## API Reference - -### Core Classes - -#### BlackBoxCore -```java -// Main entry point -BlackBoxCore core = BlackBoxCore.get(); - -// Core methods -core.installPackageAsUser(apkFile, userId); -core.uninstallPackage(packageName, userId); -core.getInstalledApps(userId); -core.isAppInstalled(packageName, userId); -``` - -#### BActivityThread -```java -// Activity thread management -int userId = BActivityThread.getUserId(); -String packageName = BActivityThread.getAppPackageName(); -String processName = BActivityThread.getAppProcessName(); -``` - -#### UIDSpoofingHelper -```java -// UID management utilities -int systemUID = UIDSpoofingHelper.getSystemUID(); -int packageUID = UIDSpoofingHelper.getPackageUID(packageName); -boolean needsSpoofing = UIDSpoofingHelper.needsUIDSpoofing(operation, packageName); -``` - -### Service Proxies - -#### WebViewProxy -```java -// WebView management -WebViewProxy.configureWebView(webView, context); -WebViewProxy.setDataDirectorySuffix(suffix); -String dataDir = WebViewProxy.getDataDirectory(); -``` - -#### WorkManagerProxy -```java -// WorkManager compatibility -WorkManagerProxy.enqueueWork(workRequest); -WorkManagerProxy.cancelWork(workId); -List workInfos = WorkManagerProxy.getWorkInfos(); -``` - -#### GoogleAccountManagerProxy -```java -// Google account management -Account[] accounts = GoogleAccountManagerProxy.getAccounts(); -String token = GoogleAccountManagerProxy.getAuthToken(account, authTokenType); -boolean success = GoogleAccountManagerProxy.addAccount(account, password, extras); -``` - ---- - -## Frequently Asked Questions - -### Q: Why do some apps show black screens? -**A**: This is usually caused by context or resource loading issues. The new BlackBox version includes comprehensive fixes for: -- Context management -- Resource loading -- Activity lifecycle -- Service initialization - -### Q: How do I fix WebView issues in browsers? -**A**: The new WebView system automatically handles: -- Data directory conflicts -- Process isolation -- Provider issues -- Cache management - -### Q: Why do background jobs fail? -**A**: Background job failures are now handled by: -- WorkManager compatibility layer -- JobScheduler UID validation bypass -- Smart UID spoofing -- Graceful fallback mechanisms - -### Q: How do I prevent app cloning issues? -**A**: BlackBox now includes: -- Automatic cloning prevention -- Package validation -- Security checks -- Error messages for blocked installations - -### Q: What if Google services don't work? -**A**: The new GMS system provides: -- Mock Google Play Services -- Account authentication fallbacks -- Token management -- Service compatibility layers - ---- - -## Support & Updates - -### Getting Help -- **Documentation**: Check this Docs.md file -- **Logs**: Enable debug mode and analyze logs -- **Community**: Join BlackBox user forums -- **Issues**: Report bugs with detailed logs - -### Version History -- **v2.0**: Complete rewrite with new architecture -- **v2.1**: WebView and browser compatibility -- **v2.2**: Google services integration -- **v2.3**: Background job management -- **Current**: UID spoofing and crash prevention - -### Future Features -- **Enhanced Security**: Additional anti-detection features -- **Performance**: Memory and CPU optimization -- **Compatibility**: Support for more Android versions -- **Integration**: Additional service proxies - ---- - -## Conclusion - -The new BlackBox virtual environment provides a robust, feature-rich solution for Android app virtualization. With comprehensive WebView support, Google services integration, and background job management, it offers enterprise-grade functionality for both developers and end users. - -For the best experience: -1. **Keep BlackBox updated** to the latest version -2. **Enable debug logging** when troubleshooting -3. **Monitor system resources** for optimal performance -4. **Report issues** with detailed logs for faster resolution - -Happy virtualizing! 🚀✨ diff --git a/README.md b/README.md index d4ac61d..aabfbbf 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,18 @@ # FridaBox -FridaBox is an authorized mobile-security research MVP that runs an original, -unmodified APK inside BlackBox virtual processes and loads Frida Gadget before +FridaBox is an authorized mobile-security research workspace that runs an original, +unmodified APK inside private virtual processes and loads Frida Gadget before the guest `Application` is created. It requires no root, frida-server, Magisk, Zygisk, system-image changes, real PackageManager installation, APK patching, repacking, or resigning. -The foundation is `ALEX5402/NewBlackbox` commit -`89b59836c66f173756a4ae258cf379a957649820`. The host application ID is -`com.qm4rs.fridabox`; existing engine namespaces remain unchanged. +The host application ID and Android namespace are both `com.qm4rs.fridabox`. +Third-party engine provenance is isolated in `THIRD_PARTY_NOTICES.md`. ## MVP capabilities - SAF import of one base APK into app-private, read-only storage. -- SHA-256 verification before and after BlackBox virtual installation. +- SHA-256 verification before and after private virtual installation. - ARM64 native-library inspection; pure Java/Kotlin guests are accepted and native guests without `arm64-v8a` are rejected. - Per-guest instrumented or non-instrumented launches with virtual process stop diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md deleted file mode 100644 index d37acde..0000000 --- a/RELEASE_NOTES.md +++ /dev/null @@ -1,106 +0,0 @@ -# Release Notes - NewBlackbox - -## Version: Latest Build (2026-01-31) - ---- - -### New Features - -#### VPN Network Mode Toggle -Added a new setting to choose between VPN and normal network mode for sandboxed apps. - -- **Location:** Settings → Others → Use VPN Network -- **Default:** OFF (normal network mode) -- When enabled, traffic is routed through BlackBox's VPN service -- Requires app restart to take effect - -**Files Changed:** -- `app/src/main/java/top/niunaijun/blackboxa/view/main/BlackBoxLoader.kt` -- `app/src/main/java/top/niunaijun/blackboxa/view/setting/SettingFragment.kt` -- `app/src/main/res/xml/setting.xml` -- `app/src/main/res/values/strings.xml` -- `Bcore/src/main/java/top/niunaijun/blackbox/app/configuration/ClientConfiguration.java` -- `Bcore/src/main/java/top/niunaijun/blackbox/BlackBoxCore.java` - -#### Device Information Logging -Added comprehensive device info header in logcat for easier debugging: -- Android version, SDK level, security patch -- Device manufacturer, brand, model, hardware -- Supported CPU/ABIs (32-bit and 64-bit) -- Memory info (heap usage) -- App version and package info -- Build fingerprint and timestamps - ---- - -### Bug Fixes - -#### VPN Permission Fix -**Problem:** VPN service failed to establish interface (`builder.establish()` returned null). - -**Root Cause:** Android requires `VpnService.prepare()` to be called from an Activity before VPN can be established. - -**Solution:** Added VPN permission request to `MainActivity.kt` on app launch. - -**Files Changed:** -- `app/src/main/java/top/niunaijun/blackboxa/view/main/MainActivity.kt` - ---- - -#### Android 10 Black Screen Fix -**Problem:** Apps would show a black screen and timeout on Android 10 (API 29). - -**Root Cause:** -- `BRAttributionSource.getRealClass()` returns `null` on Android < 31 -- `SystemProviderStub.invoke()` crashed calling `.getName()` on null class -- `ClassInvocationStub.injectHook()` crashed when `getWho()` returned null - -**Solution:** -- Added null checks in `SystemProviderStub.java` for API version checks -- Added null check in `ClassInvocationStub.java` to skip hooks when services don't exist - -**Files Changed:** -- `Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/SystemProviderStub.java` -- `Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ClassInvocationStub.java` - ---- - -### Removed Features - -#### Xposed Framework Support -- Removed `BXposedManagerService` and related AIDL interfaces -- Removed "Install Xposed Module" UI and Settings entries -- Cleaned up Xposed-related flags and package checks - ---- - -### Stability Improvements - -#### Anti-Detection Native Hook Stability -- Removed `LOGD` calls from critical native hooks to prevent infinite recursion -- Fixed syntax errors in hook implementations -- Hooks now silently return `ENOENT` for blocked paths - ---- - -### Known Issues - -#### Oppo/ColorOS Thermal Stats Error -On Oppo/ColorOS devices, you may see errors like: -``` -OppoThermalStats: PackageManager$NameNotFoundException: top.niunaijun.blackboxa:p0 -``` -**This is harmless** - it's an Oppo system bug where their thermal management incorrectly uses process names (with `:p0` suffix) instead of package names. The app works normally. - ---- - -### Compatibility - -| Android Version | Status | -|-----------------|--------| -| Android 10 (Q) | ✅ Fixed | -| Android 11 (R) | ✅ Supported | -| Android 12 (S) | ✅ Supported | -| Android 13 (T) | ✅ Supported | -| Android 14 (U) | ✅ Supported | -| Android 15+ | ✅ Supported | diff --git a/app/build.gradle b/app/build.gradle index 2736ba1..35c6e14 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,7 +15,7 @@ if (releaseSigningValues.any { it != null && !it.trim().isEmpty() } && !releaseS android { - namespace 'top.niunaijun.blackboxa' + namespace 'com.qm4rs.fridabox' compileSdk rootProject.ext.compileSdkVersion ndkVersion = "29.0.14206865" defaultConfig { @@ -170,7 +170,6 @@ tasks.named("check").configure { } dependencies { - implementation fileTree(dir: "libs", include: ["*.jar", "*.aar"]) implementation project(':Bcore') implementation libs.appcompat @@ -180,35 +179,4 @@ dependencies { testImplementation libs.junit androidTestImplementation libs.ext.junit androidTestImplementation libs.espresso.core - - implementation "androidx.preference:preference-ktx:1.1.1" - - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" - implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1" - - - implementation 'androidx.recyclerview:recyclerview:1.2.1' - implementation 'com.gitee.cbfg5210:RVAdapter:0.3.7' - - - implementation 'com.github.Othershe:CornerLabelView:1.0.0' - -// implementation 'com.github.nukc.stateview:kotlin:2.2.0' - - implementation 'com.github.Ferfalk:SimpleSearchView:0.2.0' - implementation 'com.tbuonomo:dotsindicator:4.2' - - implementation 'org.osmdroid:osmdroid-android:6.1.11' - - implementation 'com.afollestad.material-dialogs:core:3.3.0' - implementation 'com.afollestad.material-dialogs:input:3.3.0' - - - - - - - implementation 'androidx.work:work-runtime:2.7.1' - } diff --git a/app/libs/StateView-v3.0.6.aar b/app/libs/StateView-v3.0.6.aar deleted file mode 100644 index 658e6df..0000000 Binary files a/app/libs/StateView-v3.0.6.aar and /dev/null differ diff --git a/app/libs/catloading-release.aar b/app/libs/catloading-release.aar deleted file mode 100644 index 35fe2c2..0000000 Binary files a/app/libs/catloading-release.aar and /dev/null differ diff --git a/app/libs/floatingview-release.aar b/app/libs/floatingview-release.aar deleted file mode 100644 index 0edd07c..0000000 Binary files a/app/libs/floatingview-release.aar and /dev/null differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fc594fb..5ad0e7c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,13 +13,12 @@ @@ -35,28 +34,5 @@ - - - - - - - - - - - - - diff --git a/app/src/main/java/top/niunaijun/blackboxa/fridabox/ApkInspector.java b/app/src/main/java/com/qm4rs/fridabox/ApkInspector.java similarity index 97% rename from app/src/main/java/top/niunaijun/blackboxa/fridabox/ApkInspector.java rename to app/src/main/java/com/qm4rs/fridabox/ApkInspector.java index 472afb2..255e3f2 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/fridabox/ApkInspector.java +++ b/app/src/main/java/com/qm4rs/fridabox/ApkInspector.java @@ -1,4 +1,4 @@ -package top.niunaijun.blackboxa.fridabox; +package com.qm4rs.fridabox; import java.io.File; import java.io.IOException; diff --git a/app/src/main/java/top/niunaijun/blackboxa/fridabox/ApkIntegrity.java b/app/src/main/java/com/qm4rs/fridabox/ApkIntegrity.java similarity index 96% rename from app/src/main/java/top/niunaijun/blackboxa/fridabox/ApkIntegrity.java rename to app/src/main/java/com/qm4rs/fridabox/ApkIntegrity.java index 7152c57..766445f 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/fridabox/ApkIntegrity.java +++ b/app/src/main/java/com/qm4rs/fridabox/ApkIntegrity.java @@ -1,4 +1,4 @@ -package top.niunaijun.blackboxa.fridabox; +package com.qm4rs.fridabox; import java.io.File; import java.io.FileInputStream; diff --git a/app/src/main/java/top/niunaijun/blackboxa/fridabox/FridaBoxActivity.kt b/app/src/main/java/com/qm4rs/fridabox/FridaBoxActivity.kt similarity index 99% rename from app/src/main/java/top/niunaijun/blackboxa/fridabox/FridaBoxActivity.kt rename to app/src/main/java/com/qm4rs/fridabox/FridaBoxActivity.kt index 2909a81..896f64a 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/fridabox/FridaBoxActivity.kt +++ b/app/src/main/java/com/qm4rs/fridabox/FridaBoxActivity.kt @@ -1,4 +1,4 @@ -package top.niunaijun.blackboxa.fridabox +package com.qm4rs.fridabox import android.content.ClipData import android.content.ClipboardManager @@ -38,9 +38,7 @@ import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputLayout import top.niunaijun.blackbox.BlackBoxCore import top.niunaijun.blackbox.instrumentation.InstrumentationSettings -import top.niunaijun.blackboxa.BuildConfig -import top.niunaijun.blackboxa.R -import top.niunaijun.blackboxa.databinding.ActivityFridaboxBinding +import com.qm4rs.fridabox.databinding.ActivityFridaboxBinding import java.io.File import java.io.FileOutputStream import java.security.MessageDigest diff --git a/app/src/main/java/com/qm4rs/fridabox/FridaBoxApplication.kt b/app/src/main/java/com/qm4rs/fridabox/FridaBoxApplication.kt new file mode 100644 index 0000000..adedbf2 --- /dev/null +++ b/app/src/main/java/com/qm4rs/fridabox/FridaBoxApplication.kt @@ -0,0 +1,36 @@ +package com.qm4rs.fridabox + +import android.app.Application +import android.content.Context +import android.util.Log +import top.niunaijun.blackbox.BlackBoxCore + +class FridaBoxApplication : Application() { + override fun attachBaseContext(base: Context) { + super.attachBaseContext(base) + appContext = base + + runCatching { BlackBoxCore.get().closeCodeInit() } + .onFailure { Log.e(TAG, "Native bootstrap failed", it) } + runCatching { BlackBoxCore.get().onBeforeMainApplicationAttach(this, base) } + .onFailure { Log.e(TAG, "Pre-attach hook failed", it) } + + FridaBoxRuntime.attach(base) + + runCatching { BlackBoxCore.get().onAfterMainApplicationAttach(this, base) } + .onFailure { Log.e(TAG, "Post-attach hook failed", it) } + } + + override fun onCreate() { + super.onCreate() + FridaBoxRuntime.create() + } + + companion object { + private const val TAG = "FridaBox.Application" + + @Volatile + lateinit var appContext: Context + private set + } +} diff --git a/app/src/main/java/com/qm4rs/fridabox/FridaBoxRuntime.kt b/app/src/main/java/com/qm4rs/fridabox/FridaBoxRuntime.kt new file mode 100644 index 0000000..5b0c081 --- /dev/null +++ b/app/src/main/java/com/qm4rs/fridabox/FridaBoxRuntime.kt @@ -0,0 +1,66 @@ +package com.qm4rs.fridabox + +import android.app.Application +import android.content.Context +import android.util.Log +import java.io.File +import top.niunaijun.blackbox.BlackBoxCore +import top.niunaijun.blackbox.app.BActivityThread +import top.niunaijun.blackbox.app.configuration.AppLifecycleCallback +import top.niunaijun.blackbox.app.configuration.ClientConfiguration + +object FridaBoxRuntime { + private const val TAG = "FridaBox.Runtime" + + fun attach(context: Context) { + BlackBoxCore.get().doAttachBaseContext(context, object : ClientConfiguration() { + override fun getHostPackageName(): String = context.packageName + override fun isHideRoot(): Boolean = false + override fun isEnableDaemonService(): Boolean = true + override fun isUseVpnNetwork(): Boolean = false + override fun isDisableFlagSecure(): Boolean = false + override fun requestInstallPackage(file: File?, userId: Int): Boolean = false + }) + + BlackBoxCore.get().addAppLifecycleCallback(object : AppLifecycleCallback() { + override fun beforeCreateApplication( + packageName: String?, + processName: String?, + context: Context?, + userId: Int + ) { + Log.d(TAG, "beforeCreateApplication: package=$packageName process=$processName user=${BActivityThread.getUserId()}") + } + + override fun beforeApplicationOnCreate( + packageName: String?, + processName: String?, + application: Application?, + userId: Int + ) { + Log.d(TAG, "beforeApplicationOnCreate: package=$packageName process=$processName") + } + + override fun afterApplicationOnCreate( + packageName: String?, + processName: String?, + application: Application?, + userId: Int + ) { + Log.d(TAG, "afterApplicationOnCreate: package=$packageName process=$processName") + } + + override fun onStoragePermissionNeeded(packageName: String?, userId: Int): Boolean { + Log.w(TAG, "Storage permission required by guest: package=$packageName user=$userId") + return false + } + }) + } + + fun create() { + BlackBoxCore.get().doCreate() + BlackBoxCore.get().addServiceAvailableCallback { + Log.d(TAG, "Virtual runtime services are ready") + } + } +} diff --git a/app/src/main/java/top/niunaijun/blackboxa/fridabox/InstrumentationPreferenceParser.java b/app/src/main/java/com/qm4rs/fridabox/InstrumentationPreferenceParser.java similarity index 94% rename from app/src/main/java/top/niunaijun/blackboxa/fridabox/InstrumentationPreferenceParser.java rename to app/src/main/java/com/qm4rs/fridabox/InstrumentationPreferenceParser.java index 526ff44..984cc5b 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/fridabox/InstrumentationPreferenceParser.java +++ b/app/src/main/java/com/qm4rs/fridabox/InstrumentationPreferenceParser.java @@ -1,4 +1,4 @@ -package top.niunaijun.blackboxa.fridabox; +package com.qm4rs.fridabox; public final class InstrumentationPreferenceParser { private InstrumentationPreferenceParser() { diff --git a/app/src/main/java/top/niunaijun/blackboxa/app/App.kt b/app/src/main/java/top/niunaijun/blackboxa/app/App.kt deleted file mode 100644 index 5158f30..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/app/App.kt +++ /dev/null @@ -1,73 +0,0 @@ -package top.niunaijun.blackboxa.app - -import android.annotation.SuppressLint -import android.app.Application -import android.content.Context -import android.util.Log -import top.niunaijun.blackbox.BlackBoxCore - - -class App : Application() { - - companion object { - - @SuppressLint("StaticFieldLeak") - @Volatile - private lateinit var mContext: Context - - @JvmStatic - fun getContext(): Context { - return mContext - } - } - - override fun attachBaseContext(base: Context?) { - try { - super.attachBaseContext(base) - - try { - BlackBoxCore.get().closeCodeInit() - } catch (e: Exception) { - Log.e("App", "Error in closeCodeInit: ${e.message}") - } - - try { - BlackBoxCore.get().onBeforeMainApplicationAttach(this, base) - } catch (e: Exception) { - Log.e("App", "Error in onBeforeMainApplicationAttach: ${e.message}") - } - - mContext = base!! - - try { - AppManager.doAttachBaseContext(base) - } catch (e: Exception) { - Log.e("App", "Error in doAttachBaseContext: ${e.message}") - } - - try { - - BlackBoxCore.get().onAfterMainApplicationAttach(this, base) - - } catch (e: Exception) { - - Log.e("App", "Error in onAfterMainApplicationAttach: ${e.message}") - - } - } catch (e: Exception) { - Log.e("App", "Critical error in attachBaseContext: ${e.message}") - if (base != null) { - mContext = base - } - } - } - - override fun onCreate() { - try { - super.onCreate() - AppManager.doOnCreate(mContext) - } catch (e: Exception) { - Log.e("App", "Error in onCreate: ${e.message}") - } - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/app/AppManager.kt b/app/src/main/java/top/niunaijun/blackboxa/app/AppManager.kt deleted file mode 100644 index 243cc52..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/app/AppManager.kt +++ /dev/null @@ -1,71 +0,0 @@ -package top.niunaijun.blackboxa.app - -import android.content.Context -import android.content.SharedPreferences -import android.util.Log -import top.niunaijun.blackboxa.view.main.BlackBoxLoader - - -object AppManager { - private const val TAG = "AppManager" - - @JvmStatic - val mBlackBoxLoader by lazy { - try { - BlackBoxLoader() - } catch (e: Exception) { - Log.e(TAG, "Error creating BlackBoxLoader: ${e.message}") - - BlackBoxLoader() - } - } - - @JvmStatic - val mBlackBoxCore by lazy { - try { - mBlackBoxLoader.getBlackBoxCore() - } catch (e: Exception) { - Log.e(TAG, "Error getting BlackBoxCore: ${e.message}") - throw e - } - } - - @JvmStatic - val mRemarkSharedPreferences: SharedPreferences by lazy { - try { - App.getContext().getSharedPreferences("UserRemark", Context.MODE_PRIVATE) - } catch (e: Exception) { - Log.e(TAG, "Error creating SharedPreferences: ${e.message}") - throw e - } - } - - fun doAttachBaseContext(context: Context) { - try { - mBlackBoxLoader.attachBaseContext(context) - mBlackBoxLoader.addLifecycleCallback() - } catch (e: Exception) { - Log.e(TAG, "Error in doAttachBaseContext: ${e.message}") - - } - } - - fun doOnCreate(context: Context) { - try { - mBlackBoxLoader.doOnCreate(context) - initThirdService(context) - } catch (e: Exception) { - Log.e(TAG, "Error in doOnCreate: ${e.message}") - - } - } - - private fun initThirdService(context: Context) { - try { - - - } catch (e: Exception) { - Log.e(TAG, "Error in initThirdService: ${e.message}") - } - } -} diff --git a/app/src/main/java/top/niunaijun/blackboxa/app/rocker/BaseActivityLifecycleCallback.kt b/app/src/main/java/top/niunaijun/blackboxa/app/rocker/BaseActivityLifecycleCallback.kt deleted file mode 100644 index 6a5cf2b..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/app/rocker/BaseActivityLifecycleCallback.kt +++ /dev/null @@ -1,31 +0,0 @@ -package top.niunaijun.blackboxa.app.rocker - -import android.app.Activity -import android.app.Application -import android.os.Bundle - - -interface BaseActivityLifecycleCallback : Application.ActivityLifecycleCallbacks { - - override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { - - } - override fun onActivityStarted(activity: Activity) { - - } - override fun onActivityResumed(activity: Activity) { - - } - override fun onActivityPaused(activity: Activity) { - - } - override fun onActivityStopped(activity: Activity) { - - } - override fun onActivitySaveInstanceState(activity: Activity, p1: Bundle) { - - } - override fun onActivityDestroyed(activity: Activity) { - - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/app/rocker/RockerManager.kt b/app/src/main/java/top/niunaijun/blackboxa/app/rocker/RockerManager.kt deleted file mode 100644 index 4a32d27..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/app/rocker/RockerManager.kt +++ /dev/null @@ -1,226 +0,0 @@ -package top.niunaijun.blackboxa.app.rocker - -import android.app.Activity -import android.app.Application -import android.content.Context -import android.util.Log -import android.view.Gravity -import android.widget.FrameLayout -import android.widget.RelativeLayout -import com.imuxuan.floatingview.FloatingMagnetView -import com.imuxuan.floatingview.FloatingView -import kotlin.math.cos -import kotlin.math.sin -import top.niunaijun.blackbox.entity.location.BLocation -import top.niunaijun.blackbox.fake.frameworks.BLocationManager -import top.niunaijun.blackboxa.app.App -import top.niunaijun.blackboxa.widget.EnFloatView - - - -object RockerManager { - - private const val TAG = "RockerManager" - private var isInitialized = false - - - private const val Ea = 6378137.0 - private const val Eb = 6356725.0 - - fun init(application: Application?, userId: Int) { - try { - if (isInitialized) { - Log.d(TAG, "RockerManager already initialized, skipping...") - return - } - - if (application == null) { - Log.w(TAG, "Application is null, cannot initialize RockerManager") - return - } - - - if (!checkPermissions(application)) { - Log.w(TAG, "Required permissions not granted, RockerManager cannot initialize") - Log.w(TAG, "Please grant: ${getRequiredPermissions().joinToString(", ")}") - return - } - - if (!BLocationManager.isFakeLocationEnable()) { - Log.d(TAG, "Fake location is not enabled, RockerManager will not initialize") - return - } - - Log.d(TAG, "Initializing RockerManager for userId: $userId") - - val enFloatView = initFloatView() - if (enFloatView is EnFloatView) { - enFloatView.setListener { angle: Float, distance: Float -> - changeLocation(distance, angle, application.packageName, userId) - } - Log.d(TAG, "Floating view initialized successfully") - } else { - Log.w(TAG, "Failed to initialize floating view") - return - } - - - application.registerActivityLifecycleCallbacks( - object : BaseActivityLifecycleCallback { - override fun onActivityStarted(activity: Activity) { - super.onActivityStarted(activity) - try { - FloatingView.get().attach(activity) - Log.d( - TAG, - "Floating view attached to activity: ${activity.javaClass.simpleName}" - ) - } catch (e: Exception) { - Log.e( - TAG, - "Error attaching floating view to activity: ${e.message}" - ) - } - } - - override fun onActivityStopped(activity: Activity) { - super.onActivityStopped(activity) - try { - FloatingView.get().detach(activity) - Log.d( - TAG, - "Floating view detached from activity: ${activity.javaClass.simpleName}" - ) - } catch (e: Exception) { - Log.e( - TAG, - "Error detaching floating view from activity: ${e.message}" - ) - } - } - } - ) - - isInitialized = true - Log.d( - TAG, - "RockerManager initialized successfully - Floating GPS joystick is now active!" - ) - } catch (e: Exception) { - Log.e(TAG, "Error initializing RockerManager: ${e.message}") - Log.e(TAG, "Stack trace: ", e) - } - } - - private fun initFloatView(): FloatingMagnetView? { - return try { - val params = - FrameLayout.LayoutParams( - RelativeLayout.LayoutParams.WRAP_CONTENT, - RelativeLayout.LayoutParams.WRAP_CONTENT - ) - - params.gravity = Gravity.START or Gravity.CENTER - val view = EnFloatView(App.getContext()) - view.layoutParams = params - - FloatingView.get().customView(view) - Log.d(TAG, "Floating view created successfully") - - FloatingView.get().view - } catch (e: Exception) { - Log.e(TAG, "Error creating floating view: ${e.message}") - null - } - } - - private fun changeLocation(distance: Float, angle: Float, packageName: String, userId: Int) { - try { - val location = BLocationManager.get().getLocation(userId, packageName) - if (location == null) { - Log.w(TAG, "No current location found for package: $packageName, userId: $userId") - return - } - - Log.d( - TAG, - "Changing location - Distance: ${distance}m, Angle: ${angle}°, Current: ${location.latitude}, ${location.longitude}" - ) - - - val dx = distance * sin(angle * Math.PI / 180.0) - val dy = distance * cos(angle * Math.PI / 180.0) - - - val ec = Eb + (Ea - Eb) * (90.0 - location.latitude) / 90.0 - val ed = ec * cos(location.latitude * Math.PI / 180) - - val newLng = (dx / ed + location.longitude * Math.PI / 180.0) * 180.0 / Math.PI - val newLat = (dy / ec + location.latitude * Math.PI / 180.0) * 180.0 / Math.PI - - val newLocation = BLocation(newLat, newLng) - - - BLocationManager.get().setLocation(userId, packageName, newLocation) - - Log.d(TAG, "Location updated - New: ${newLat}, ${newLng}") - } catch (e: Exception) { - Log.e(TAG, "Error changing location: ${e.message}") - Log.e(TAG, "Stack trace: ", e) - } - } - - - fun isActive(): Boolean { - return isInitialized - } - - - fun checkPermissions(context: Context): Boolean { - return try { - - val hasOverlayPermission = android.provider.Settings.canDrawOverlays(context) - if (!hasOverlayPermission) { - Log.w( - TAG, - "Overlay permission not granted - RockerManager cannot show floating view" - ) - return false - } - - - val hasLocationPermission = - context.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) == - android.content.pm.PackageManager.PERMISSION_GRANTED - if (!hasLocationPermission) { - Log.w(TAG, "Location permission not granted - RockerManager cannot access location") - return false - } - - Log.d(TAG, "All required permissions are granted") - true - } catch (e: Exception) { - Log.e(TAG, "Error checking permissions: ${e.message}") - false - } - } - - - fun getRequiredPermissions(): List { - return listOf( - android.Manifest.permission.SYSTEM_ALERT_WINDOW, - android.Manifest.permission.ACCESS_FINE_LOCATION, - android.Manifest.permission.ACCESS_COARSE_LOCATION - ) - } - - - fun cleanup() { - try { - isInitialized = false - Log.d(TAG, "RockerManager cleaned up") - } catch (e: Exception) { - Log.e(TAG, "Error during cleanup: ${e.message}") - } - } -} diff --git a/app/src/main/java/top/niunaijun/blackboxa/bean/AppInfo.kt b/app/src/main/java/top/niunaijun/blackboxa/bean/AppInfo.kt deleted file mode 100644 index 38f719d..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/bean/AppInfo.kt +++ /dev/null @@ -1,6 +0,0 @@ -package top.niunaijun.blackboxa.bean - -import android.graphics.drawable.Drawable - - -data class AppInfo(val name:String,val icon:Drawable?,val packageName:String,val sourceDir:String,val isXpModule:Boolean) \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/bean/FakeLocationBean.kt b/app/src/main/java/top/niunaijun/blackboxa/bean/FakeLocationBean.kt deleted file mode 100644 index 1aa4b1c..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/bean/FakeLocationBean.kt +++ /dev/null @@ -1,15 +0,0 @@ -package top.niunaijun.blackboxa.bean - -import android.graphics.drawable.Drawable -import top.niunaijun.blackbox.entity.location.BLocation - -data class FakeLocationBean( - val userID: Int, - val name: String, - val icon: Drawable, - val packageName: String, - var fakeLocationPattern: Int, - var fakeLocation: BLocation? -) - -data class FakeLocationBeanInstallBean(val userID: Int, val success: Boolean, val msg: String) \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/bean/GmsBean.kt b/app/src/main/java/top/niunaijun/blackboxa/bean/GmsBean.kt deleted file mode 100644 index c1bc3fa..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/bean/GmsBean.kt +++ /dev/null @@ -1,7 +0,0 @@ -package top.niunaijun.blackboxa.bean - - -data class GmsBean(val userID:Int,val userName:String,var isInstalledGms:Boolean) - - -data class GmsInstallBean(val userID: Int,val success:Boolean,val msg:String) \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/bean/InstalledAppBean.kt b/app/src/main/java/top/niunaijun/blackboxa/bean/InstalledAppBean.kt deleted file mode 100644 index 4731075..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/bean/InstalledAppBean.kt +++ /dev/null @@ -1,6 +0,0 @@ -package top.niunaijun.blackboxa.bean - -import android.graphics.drawable.Drawable - - -data class InstalledAppBean(val name:String, val icon: Drawable?, val packageName:String, val sourceDir:String, val isInstall:Boolean) diff --git a/app/src/main/java/top/niunaijun/blackboxa/bean/XpModuleInfo.kt b/app/src/main/java/top/niunaijun/blackboxa/bean/XpModuleInfo.kt deleted file mode 100644 index 6dabeca..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/bean/XpModuleInfo.kt +++ /dev/null @@ -1,13 +0,0 @@ -package top.niunaijun.blackboxa.bean - -import android.graphics.drawable.Drawable - - -data class XpModuleInfo( - val name: String, - val desc: String, - val packageName: String, - val version: String, - var enable:Boolean, - val icon: Drawable -) diff --git a/app/src/main/java/top/niunaijun/blackboxa/biz/cache/AppSharedPreferenceDelegate.kt b/app/src/main/java/top/niunaijun/blackboxa/biz/cache/AppSharedPreferenceDelegate.kt deleted file mode 100644 index 425b62b..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/biz/cache/AppSharedPreferenceDelegate.kt +++ /dev/null @@ -1,71 +0,0 @@ -package top.niunaijun.blackboxa.biz.cache - -import android.content.Context -import android.text.TextUtils -import androidx.core.content.edit -import kotlin.properties.ReadWriteProperty -import kotlin.reflect.KProperty - - -open class AppSharedPreferenceDelegate( - context: Context, - private val default: Data, - spName: String? = null -) : ReadWriteProperty { - - private val mSharedPreferences by lazy { - val tmpCacheName = - if (TextUtils.isEmpty(spName)) { - AppSharedPreferenceDelegate::class.java.simpleName - } else { - spName - } - return@lazy context.getSharedPreferences(tmpCacheName, Context.MODE_PRIVATE) - } - - override fun getValue(thisRef: Any, property: KProperty<*>): Data { - return findData(property.name, default) - } - - override fun setValue(thisRef: Any, property: KProperty<*>, value: Data?) { - putData(property.name, value) - } - - protected fun findData(key: String, default: Data): Data { - with(mSharedPreferences) { - val result: Any = - when (default) { - is Int -> getInt(key, default) - is Long -> getLong(key, default) - is Float -> getFloat(key, default) - is String -> getString(key, default)!! - is Boolean -> getBoolean(key, default) - else -> - throw IllegalArgumentException( - "This type $default can not be saved into sharedPreferences" - ) - } - return result as? Data ?: default - } - } - - protected fun putData(key: String, value: Data?) { - mSharedPreferences.edit { - if (value == null) { - remove(key) - } else { - when (value) { - is Int -> putInt(key, value) - is Long -> putLong(key, value) - is Float -> putFloat(key, value) - is String -> putString(key, value) - is Boolean -> putBoolean(key, value) - else -> - throw IllegalArgumentException( - "This type $default can not be saved into Preferences" - ) - } - } - } - } -} diff --git a/app/src/main/java/top/niunaijun/blackboxa/data/AppsRepository.kt b/app/src/main/java/top/niunaijun/blackboxa/data/AppsRepository.kt deleted file mode 100644 index 29df428..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/data/AppsRepository.kt +++ /dev/null @@ -1,509 +0,0 @@ -package top.niunaijun.blackboxa.data - -import android.content.pm.ApplicationInfo -import android.net.Uri -import android.util.Log -import android.webkit.URLUtil -import androidx.lifecycle.MutableLiveData -import java.io.File -import top.niunaijun.blackbox.BlackBoxCore -import top.niunaijun.blackbox.utils.AbiUtils -import top.niunaijun.blackboxa.R -import top.niunaijun.blackboxa.app.AppManager -import top.niunaijun.blackboxa.bean.AppInfo -import top.niunaijun.blackboxa.bean.InstalledAppBean -import top.niunaijun.blackboxa.util.MemoryManager -import top.niunaijun.blackboxa.util.getString - - -class AppsRepository { - val TAG: String = "AppsRepository" - private var mInstalledList = mutableListOf() - - - private fun safeLoadAppLabel(applicationInfo: ApplicationInfo): String { - return try { - BlackBoxCore.getPackageManager().getApplicationLabel(applicationInfo).toString() - } catch (e: Exception) { - Log.w(TAG, "Failed to load label for ${applicationInfo.packageName}: ${e.message}") - applicationInfo.packageName - } - } - - - private fun safeLoadAppIcon( - applicationInfo: ApplicationInfo - ): android.graphics.drawable.Drawable? { - return try { - - if (MemoryManager.shouldSkipIconLoading()) { - Log.w( - TAG, - "Memory usage high (${MemoryManager.getMemoryUsagePercentage()}%), skipping icon for ${applicationInfo.packageName}" - ) - return null - } - - val icon = BlackBoxCore.getPackageManager().getApplicationIcon(applicationInfo) - - - if (icon is android.graphics.drawable.BitmapDrawable) { - val bitmap = icon.bitmap - - if (bitmap.width > 96 || bitmap.height > 96) { - try { - val scaledBitmap = - android.graphics.Bitmap.createScaledBitmap(bitmap, 96, 96, true) - android.graphics.drawable.BitmapDrawable( - BlackBoxCore.getPackageManager() - .getResourcesForApplication(applicationInfo.packageName), - scaledBitmap - ) - } catch (e: Exception) { - Log.w( - TAG, - "Failed to scale icon for ${applicationInfo.packageName}: ${e.message}" - ) - icon - } - } else { - icon - } - } else { - icon - } - } catch (e: Exception) { - Log.w(TAG, "Failed to load icon for ${applicationInfo.packageName}: ${e.message}") - null - } - } - - fun previewInstallList() { - try { - synchronized(mInstalledList) { - val installedApplications: List = - BlackBoxCore.getPackageManager().getInstalledApplications(0) - val installedList = mutableListOf() - - for (installedApplication in installedApplications) { - try { - val file = File(installedApplication.sourceDir) - - if ((installedApplication.flags and ApplicationInfo.FLAG_SYSTEM) != 0) - continue - - if (!AbiUtils.isSupport(file)) continue - - - if (BlackBoxCore.get().isBlackBoxApp(installedApplication.packageName)) { - Log.d( - TAG, - "Filtering out BlackBox app: ${installedApplication.packageName}" - ) - continue - } - - val isXpModule = false - - val info = - AppInfo( - safeLoadAppLabel(installedApplication), - safeLoadAppIcon( - installedApplication - ), - installedApplication.packageName, - installedApplication.sourceDir, - isXpModule - ) - installedList.add(info) - } catch (e: Exception) { - Log.e( - TAG, - "Error processing app ${installedApplication.packageName}: ${e.message}" - ) - } - } - this.mInstalledList.clear() - this.mInstalledList.addAll(installedList) - } - } catch (e: Exception) { - Log.e(TAG, "Error in previewInstallList: ${e.message}") - } - } - - fun getInstalledAppList( - userID: Int, - loadingLiveData: MutableLiveData, - appsLiveData: MutableLiveData> - ) { - try { - loadingLiveData.postValue(true) - synchronized(mInstalledList) { - val blackBoxCore = BlackBoxCore.get() - Log.d(TAG, mInstalledList.joinToString(",")) - val newInstalledList = - mInstalledList.map { - InstalledAppBean( - it.name, - it.icon, - it.packageName, - it.sourceDir, - blackBoxCore.isInstalled(it.packageName, userID) - ) - } - appsLiveData.postValue(newInstalledList) - loadingLiveData.postValue(false) - } - } catch (e: Exception) { - Log.e(TAG, "Error in getInstalledAppList: ${e.message}") - loadingLiveData.postValue(false) - appsLiveData.postValue(emptyList()) - } - } - - fun getVmInstallList(userId: Int, appsLiveData: MutableLiveData>) { - try { - - if (MemoryManager.isMemoryCritical()) { - Log.w( - TAG, - "Memory critical (${MemoryManager.getMemoryUsagePercentage()}%), forcing garbage collection" - ) - MemoryManager.forceGarbageCollectionIfNeeded() - } - - val blackBoxCore = BlackBoxCore.get() - - - val users = blackBoxCore.users - Log.d(TAG, "getVmInstallList: userId=$userId, total users=${users.size}") - users.forEach { user -> Log.d(TAG, "User: id=${user.id}, name=${user.name}") } - - val sortListData = AppManager.mRemarkSharedPreferences.getString("AppList$userId", "") - val sortList = sortListData?.split(",") - - - var applicationList: List? = null - var retryCount = 0 - val maxRetries = 3 - - while (applicationList == null && retryCount < maxRetries) { - try { - applicationList = blackBoxCore.getInstalledApplications(0, userId) - if (applicationList == null) { - Log.w( - TAG, - "getVmInstallList: Attempt ${retryCount + 1} returned null, retrying..." - ) - retryCount++ - Thread.sleep(100) - } - } catch (e: Exception) { - Log.e( - TAG, - "getVmInstallList: Error getting applications on attempt ${retryCount + 1}: ${e.message}" - ) - retryCount++ - if (retryCount < maxRetries) { - Thread.sleep(200) - } - } - } - - - if (applicationList == null) { - Log.e( - TAG, - "getVmInstallList: applicationList is null for userId=$userId after $maxRetries attempts" - ) - appsLiveData.postValue(emptyList()) - return - } - - - Log.d( - TAG, - "getVmInstallList: userId=$userId, applicationList.size=${applicationList.size}" - ) - if (applicationList.isNotEmpty()) { - Log.d(TAG, "First app: ${applicationList.first().packageName}") - } else { - Log.w(TAG, "getVmInstallList: No applications found for userId=$userId") - } - - val appInfoList = mutableListOf() - - - val sortedApplicationList = - if (!sortList.isNullOrEmpty()) { - try { - applicationList.sortedWith(AppsSortComparator(sortList)) - } catch (e: Exception) { - Log.e(TAG, "getVmInstallList: Error sorting applications: ${e.message}") - applicationList - } - } else { - applicationList - } - - - sortedApplicationList.forEachIndexed { index, applicationInfo -> - try { - - if (index > 0 && index % 25 == 0) { - if (MemoryManager.isMemoryCritical()) { - Log.w(TAG, "Memory critical during processing, forcing GC") - MemoryManager.forceGarbageCollectionIfNeeded() - } - } - - - if (applicationInfo == null) { - Log.w( - TAG, - "getVmInstallList: Skipping null applicationInfo at index $index" - ) - return@forEachIndexed - } - - - if (applicationInfo.packageName.isNullOrBlank()) { - Log.w( - TAG, - "getVmInstallList: Skipping app with null/blank package name at index $index" - ) - return@forEachIndexed - } - - val info = - AppInfo( - safeLoadAppLabel(applicationInfo), - safeLoadAppIcon( - applicationInfo - ), - applicationInfo.packageName, - applicationInfo.sourceDir ?: "", - false - ) - - appInfoList.add(info) - - - if (index > 0 && index % 50 == 0) { - Log.d( - TAG, - "getVmInstallList: Processed $index/${sortedApplicationList.size} apps - ${MemoryManager.getMemoryInfo()}" - ) - } - } catch (e: Exception) { - Log.e( - TAG, - "getVmInstallList: Error processing app at index $index (${applicationInfo?.packageName}): ${e.message}" - ) - - } - } - - Log.d( - TAG, - "getVmInstallList: processed ${appInfoList.size} apps - ${MemoryManager.getMemoryInfo()}" - ) - - - - if (appInfoList.isEmpty()) { - Log.d( - TAG, - "getVmInstallList: No virtual apps found for userId=$userId, showing empty list (correct for new users)" - ) - } else { - Log.d( - TAG, - "getVmInstallList: Showing ${appInfoList.size} virtual apps for userId=$userId" - ) - } - - - try { - appsLiveData.postValue(appInfoList) - } catch (e: Exception) { - Log.e(TAG, "getVmInstallList: Error posting to LiveData: ${e.message}") - - try { - android.os.Handler(android.os.Looper.getMainLooper()).post { - try { - appsLiveData.postValue(appInfoList) - } catch (e2: Exception) { - Log.e( - TAG, - "getVmInstallList: Fallback posting also failed: ${e2.message}" - ) - } - } - } catch (e3: Exception) { - Log.e( - TAG, - "getVmInstallList: Could not schedule fallback posting: ${e3.message}" - ) - } - } - } catch (e: Exception) { - Log.e(TAG, "Error in getVmInstallList: ${e.message}") - try { - appsLiveData.postValue(emptyList()) - } catch (e2: Exception) { - Log.e(TAG, "getVmInstallList: Error posting empty list: ${e2.message}") - } - } - } - - fun installApk(source: String, userId: Int, resultLiveData: MutableLiveData) { - try { - - if (source.contains("blackbox") || - source.contains("niunaijun") || - source.contains("vspace") || - source.contains("virtual") - ) { - - try { - val blackBoxCore = BlackBoxCore.get() - val hostPackageName = BlackBoxCore.getHostPkg() - - - if (!URLUtil.isValidUrl(source)) { - val file = File(source) - if (file.exists()) { - val packageInfo = - BlackBoxCore.getPackageManager() - .getPackageArchiveInfo(source, 0) - if (packageInfo != null && packageInfo.packageName == hostPackageName) { - resultLiveData.postValue( - "Cannot install BlackBox app from within BlackBox. This would create infinite recursion and is not allowed for security reasons." - ) - return - } - } - } - } catch (e: Exception) { - Log.w(TAG, "Could not verify if this is BlackBox app: ${e.message}") - } - } - - val blackBoxCore = BlackBoxCore.get() - val installResult = - if (URLUtil.isValidUrl(source)) { - val uri = Uri.parse(source) - blackBoxCore.installPackageAsUser(uri, userId) - } else { - blackBoxCore.installPackageAsUser(source, userId) - } - - if (installResult.success) { - updateAppSortList(userId, installResult.packageName, true) - resultLiveData.postValue(getString(R.string.install_success)) - } else { - resultLiveData.postValue(getString(R.string.install_fail, installResult.msg)) - } - scanUser() - } catch (e: Exception) { - Log.e(TAG, "Error installing APK: ${e.message}") - resultLiveData.postValue("Installation failed: ${e.message}") - } - } - - fun unInstall(packageName: String, userID: Int, resultLiveData: MutableLiveData) { - try { - BlackBoxCore.get().uninstallPackageAsUser(packageName, userID) - updateAppSortList(userID, packageName, false) - scanUser() - resultLiveData.postValue(getString(R.string.uninstall_success)) - } catch (e: Exception) { - Log.e(TAG, "Error uninstalling APK: ${e.message}") - resultLiveData.postValue("Uninstallation failed: ${e.message}") - } - } - - fun launchApk(packageName: String, userId: Int, launchLiveData: MutableLiveData) { - try { - val result = BlackBoxCore.get().launchApk(packageName, userId) - launchLiveData.postValue(result) - } catch (e: Exception) { - Log.e(TAG, "Error launching APK: ${e.message}") - launchLiveData.postValue(false) - } - } - - fun clearApkData(packageName: String, userID: Int, resultLiveData: MutableLiveData) { - try { - BlackBoxCore.get().clearPackage(packageName, userID) - resultLiveData.postValue(getString(R.string.clear_success)) - } catch (e: Exception) { - Log.e(TAG, "Error clearing APK data: ${e.message}") - resultLiveData.postValue("Clear failed: ${e.message}") - } - } - - - private fun scanUser() { - try { - val blackBoxCore = BlackBoxCore.get() - val userList = blackBoxCore.users - - if (userList.isEmpty()) { - return - } - - val id = userList.last().id - - if (blackBoxCore.getInstalledApplications(0, id).isEmpty()) { - blackBoxCore.deleteUser(id) - AppManager.mRemarkSharedPreferences.edit().apply { - remove("Remark$id") - remove("AppList$id") - apply() - } - scanUser() - } - } catch (e: Exception) { - Log.e(TAG, "Error in scanUser: ${e.message}") - } - } - - - private fun updateAppSortList(userID: Int, pkg: String, isAdd: Boolean) { - try { - val savedSortList = AppManager.mRemarkSharedPreferences.getString("AppList$userID", "") - - val sortList = linkedSetOf() - if (savedSortList != null) { - sortList.addAll(savedSortList.split(",")) - } - - if (isAdd) { - sortList.add(pkg) - } else { - sortList.remove(pkg) - } - - AppManager.mRemarkSharedPreferences.edit().apply { - putString("AppList$userID", sortList.joinToString(",")) - apply() - } - } catch (e: Exception) { - Log.e(TAG, "Error updating app sort list: ${e.message}") - } - } - - - fun updateApkOrder(userID: Int, dataList: List) { - try { - AppManager.mRemarkSharedPreferences.edit().apply { - putString("AppList$userID", dataList.joinToString(",") { it.packageName }) - apply() - } - } catch (e: Exception) { - Log.e(TAG, "Error updating APK order: ${e.message}") - } - } -} diff --git a/app/src/main/java/top/niunaijun/blackboxa/data/AppsSortCompon.kt b/app/src/main/java/top/niunaijun/blackboxa/data/AppsSortCompon.kt deleted file mode 100644 index c792e36..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/data/AppsSortCompon.kt +++ /dev/null @@ -1,17 +0,0 @@ -package top.niunaijun.blackboxa.data - -import android.content.pm.ApplicationInfo - - -class AppsSortComparator(private val sortedList: List) : Comparator { - override fun compare(o1: ApplicationInfo?, o2: ApplicationInfo?): Int { - if (o1 == null || o2 == null) { - return 0 - } - - val first = sortedList.indexOf(o1.packageName) - val second = sortedList.indexOf(o2.packageName) - return first - second - - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/data/FakeLocationRepository.kt b/app/src/main/java/top/niunaijun/blackboxa/data/FakeLocationRepository.kt deleted file mode 100644 index a7e8f29..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/data/FakeLocationRepository.kt +++ /dev/null @@ -1,62 +0,0 @@ -package top.niunaijun.blackboxa.data - -import android.content.pm.ApplicationInfo -import android.util.Log -import androidx.lifecycle.MutableLiveData -import top.niunaijun.blackbox.BlackBoxCore -import top.niunaijun.blackbox.entity.location.BLocation -import top.niunaijun.blackbox.fake.frameworks.BLocationManager -import top.niunaijun.blackboxa.bean.FakeLocationBean - - -class FakeLocationRepository { - val TAG: String = "FakeLocationRepository" - - fun setPattern(userId: Int, pkg: String, pattern: Int) { - BLocationManager.get().setPattern(userId, pkg, pattern) - } - - private fun getPattern(userId: Int, pkg: String): Int { - return BLocationManager.get().getPattern(userId, pkg) - } - - private fun getLocation(userId: Int, pkg: String): BLocation? { - return BLocationManager.get().getLocation(userId, pkg) - } - - fun setLocation(userId: Int, pkg: String, location: BLocation) { - BLocationManager.get().setLocation(userId, pkg, location) - } - - fun getInstalledAppList( - userID: Int, - appsFakeLiveData: MutableLiveData> - ) { - val installedList = mutableListOf() - val installedApplications: List = - BlackBoxCore.get().getInstalledApplications(0, userID) - - for (installedApplication in installedApplications) { - - - - - - - - - val info = FakeLocationBean( - userID, - installedApplication.loadLabel(BlackBoxCore.getPackageManager()).toString(), - installedApplication.loadIcon(BlackBoxCore.getPackageManager()), - installedApplication.packageName, - getPattern(userID, installedApplication.packageName), - getLocation(userID, installedApplication.packageName) - ) - installedList.add(info) - } - - Log.d(TAG, installedList.joinToString(",")) - appsFakeLiveData.postValue(installedList) - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/data/GmsRepository.kt b/app/src/main/java/top/niunaijun/blackboxa/data/GmsRepository.kt deleted file mode 100644 index d5b06fe..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/data/GmsRepository.kt +++ /dev/null @@ -1,65 +0,0 @@ -package top.niunaijun.blackboxa.data - -import androidx.lifecycle.MutableLiveData -import top.niunaijun.blackbox.BlackBoxCore -import top.niunaijun.blackboxa.R -import top.niunaijun.blackboxa.app.AppManager -import top.niunaijun.blackboxa.bean.GmsBean -import top.niunaijun.blackboxa.bean.GmsInstallBean -import top.niunaijun.blackboxa.util.getString - - -class GmsRepository { - - - fun getGmsInstalledList(mInstalledLiveData: MutableLiveData>) { - val userList = arrayListOf() - - BlackBoxCore.get().users.forEach { - val userId = it.id - val userName = - AppManager.mRemarkSharedPreferences.getString("Remark$userId", "User $userId") ?: "" - val isInstalled = BlackBoxCore.get().isInstallGms(userId) - val bean = GmsBean(userId, userName, isInstalled) - userList.add(bean) - } - - mInstalledLiveData.postValue(userList) - } - - fun installGms( - userID: Int, - mUpdateInstalledLiveData: MutableLiveData - ) { - val installResult = BlackBoxCore.get().installGms(userID) - - val result = if (installResult.success) { - getString(R.string.install_success) - } else { - getString(R.string.install_fail, installResult.msg) - } - - val bean = GmsInstallBean(userID,installResult.success,result) - mUpdateInstalledLiveData.postValue(bean) - } - - fun uninstallGms( - userID: Int, - mUpdateInstalledLiveData: MutableLiveData - ) { - var isSuccess = false - if (BlackBoxCore.get().isInstallGms(userID)) { - isSuccess = BlackBoxCore.get().uninstallGms(userID) - } - - val result = if (isSuccess) { - getString(R.string.uninstall_success) - } else { - getString(R.string.uninstall_fail) - } - - val bean = GmsInstallBean(userID,isSuccess,result) - - mUpdateInstalledLiveData.postValue(bean) - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/ContextUtil.kt b/app/src/main/java/top/niunaijun/blackboxa/util/ContextUtil.kt deleted file mode 100644 index 885f4f1..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/util/ContextUtil.kt +++ /dev/null @@ -1,18 +0,0 @@ -package top.niunaijun.blackboxa.util - -import android.content.Context -import android.content.Intent -import android.net.Uri -import android.provider.Settings - - -object ContextUtil { - - fun Context.openAppSystemSettings() { - startActivity(Intent().apply { - action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - data = Uri.fromParts("package", packageName, null) - }) - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/InjectionUtil.kt b/app/src/main/java/top/niunaijun/blackboxa/util/InjectionUtil.kt deleted file mode 100644 index 8ecc02d..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/util/InjectionUtil.kt +++ /dev/null @@ -1,40 +0,0 @@ -package top.niunaijun.blackboxa.util - -import top.niunaijun.blackboxa.data.AppsRepository -import top.niunaijun.blackboxa.data.FakeLocationRepository -import top.niunaijun.blackboxa.data.GmsRepository - -import top.niunaijun.blackboxa.view.apps.AppsFactory -import top.niunaijun.blackboxa.view.fake.FakeLocationFactory -import top.niunaijun.blackboxa.view.gms.GmsFactory -import top.niunaijun.blackboxa.view.list.ListFactory - - - -object InjectionUtil { - - private val appsRepository = AppsRepository() - - - - private val gmsRepository = GmsRepository() - - private val fakeLocationRepository = FakeLocationRepository() - - fun getAppsFactory() : AppsFactory { - return AppsFactory(appsRepository) - } - - fun getListFactory(): ListFactory { - return ListFactory(appsRepository) - } - - - fun getGmsFactory():GmsFactory{ - return GmsFactory(gmsRepository) - } - - fun getFakeLocationFactory():FakeLocationFactory{ - return FakeLocationFactory(fakeLocationRepository) - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/MathUtil.java b/app/src/main/java/top/niunaijun/blackboxa/util/MathUtil.java deleted file mode 100644 index 76df8fb..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/util/MathUtil.java +++ /dev/null @@ -1,47 +0,0 @@ -package top.niunaijun.blackboxa.util; - -import android.graphics.Point; -import android.graphics.PointF; - -public class MathUtil { - - public MathUtil() { - } - - - public static int getDistance(PointF A, PointF B) { - return (int) Math.sqrt(Math.pow(A.x - B.x, 2) + Math.pow(A.y - B.y, 2)); - } - - - public static int getDistance(float x1, float y1, float x2, float y2) { - return (int) Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); - } - - - public static Point getPointByCutLength(Point A, Point B, int cutLength) { - float radian = getRadian(A, B); - return new Point(A.x + (int) (cutLength * Math.cos(radian)), A.y + (int) (cutLength * Math.sin(radian))); - } - - - public static float getRadian(Point A, Point B) { - float lenA = B.x - A.x; - float lenB = B.y - A.y; - float lenC = (float) Math.sqrt(lenA * lenA + lenB * lenB); - float radian = (float) Math.acos(lenA / lenC); - radian = radian * (B.y < A.y ? -1 : 1); - return radian; - } - - - - public static double angle2Radian(double angle) { - return angle / 180 * Math.PI; - } - - - public static double radian2Angle(double radian) { - return radian / Math.PI * 180; - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/MemoryManager.kt b/app/src/main/java/top/niunaijun/blackboxa/util/MemoryManager.kt deleted file mode 100644 index 46e0fd1..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/util/MemoryManager.kt +++ /dev/null @@ -1,128 +0,0 @@ -package top.niunaijun.blackboxa.util - -import android.util.Log -import java.lang.Runtime - - - -object MemoryManager { - - private const val TAG = "MemoryManager" - private const val MEMORY_THRESHOLD = 0.8 - private const val CRITICAL_MEMORY_THRESHOLD = 0.9 - - - fun isMemorySafe(): Boolean { - return try { - val runtime = Runtime.getRuntime() - val usedMemory = runtime.totalMemory() - runtime.freeMemory() - val maxMemory = runtime.maxMemory() - val memoryUsage = usedMemory.toDouble() / maxMemory.toDouble() - - memoryUsage < MEMORY_THRESHOLD - } catch (e: Exception) { - Log.e(TAG, "Error checking memory: ${e.message}") - true - } - } - - - fun isMemoryCritical(): Boolean { - return try { - val runtime = Runtime.getRuntime() - val usedMemory = runtime.totalMemory() - runtime.freeMemory() - val maxMemory = runtime.maxMemory() - val memoryUsage = usedMemory.toDouble() / maxMemory.toDouble() - - memoryUsage > CRITICAL_MEMORY_THRESHOLD - } catch (e: Exception) { - Log.e(TAG, "Error checking critical memory: ${e.message}") - false - } - } - - - fun getMemoryUsagePercentage(): Int { - return try { - val runtime = Runtime.getRuntime() - val usedMemory = runtime.totalMemory() - runtime.freeMemory() - val maxMemory = runtime.maxMemory() - val memoryUsage = usedMemory.toDouble() / maxMemory.toDouble() - - (memoryUsage * 100).toInt() - } catch (e: Exception) { - Log.e(TAG, "Error getting memory usage: ${e.message}") - 0 - } - } - - - fun forceGarbageCollectionIfNeeded(): Boolean { - return try { - if (isMemoryCritical()) { - Log.w( - TAG, - "Memory usage critical (${getMemoryUsagePercentage()}%), forcing garbage collection" - ) - System.gc() - Thread.sleep(100) - true - } else { - false - } - } catch (e: Exception) { - Log.e(TAG, "Error during garbage collection: ${e.message}") - false - } - } - - - fun optimizeMemoryForRecyclerView() { - try { - val memoryUsage = getMemoryUsagePercentage() - - if (memoryUsage > 70) { - Log.d(TAG, "Memory usage high (${memoryUsage}%), optimizing for RecyclerView") - - - System.gc() - - - try { - val runtime = Runtime.getRuntime() - runtime.gc() - } catch (e: Exception) { - Log.w(TAG, "Could not force runtime GC: ${e.message}") - } - } - } catch (e: Exception) { - Log.e(TAG, "Error optimizing memory: ${e.message}") - } - } - - - fun shouldSkipIconLoading(): Boolean { - return try { - val memoryUsage = getMemoryUsagePercentage() - memoryUsage > 75 - } catch (e: Exception) { - Log.e(TAG, "Error checking if should skip icon loading: ${e.message}") - false - } - } - - - fun getMemoryInfo(): String { - return try { - val runtime = Runtime.getRuntime() - val totalMemory = runtime.totalMemory() - val freeMemory = runtime.freeMemory() - val usedMemory = totalMemory - freeMemory - val maxMemory = runtime.maxMemory() - - "Memory: ${usedMemory / 1024 / 1024}MB used / ${maxMemory / 1024 / 1024}MB max (${getMemoryUsagePercentage()}%)" - } catch (e: Exception) { - "Memory: Unknown (${e.message})" - } - } -} diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/ResUtil.kt b/app/src/main/java/top/niunaijun/blackboxa/util/ResUtil.kt deleted file mode 100644 index 3eddbef..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/util/ResUtil.kt +++ /dev/null @@ -1,13 +0,0 @@ -package top.niunaijun.blackboxa.util - -import androidx.annotation.StringRes -import top.niunaijun.blackboxa.app.App - - -fun getString(@StringRes id:Int,vararg arg:String):String{ - if(arg.isEmpty()){ - return App.getContext().getString(id) - } - return App.getContext().getString(id,*arg) -} - diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/Resolution.java b/app/src/main/java/top/niunaijun/blackboxa/util/Resolution.java deleted file mode 100644 index 1e7f2c6..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/util/Resolution.java +++ /dev/null @@ -1,237 +0,0 @@ -package top.niunaijun.blackboxa.util; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.app.KeyguardManager; -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Point; -import android.os.Build; -import android.os.Handler; -import android.util.DisplayMetrics; -import android.view.Display; -import android.view.View; -import android.view.WindowManager; -import android.view.inputmethod.InputMethodManager; - -import java.lang.reflect.Field; - -public class Resolution { - private static final String TAG = "UtilsScreen"; - - - public static int getScreenWidth(Context context) { - return getScreenSize(context, null).x; - } - - - public static int getScreenHeight(Context context) { - return getScreenSize(context, null).y; - } - - - @SuppressLint("NewApi") - public static Point getScreenSize(Context context, Point outSize) { - WindowManager wm = (WindowManager) context - .getSystemService(Context.WINDOW_SERVICE); - Point ret = outSize == null ? new Point() : outSize; - - if (Build.VERSION.SDK_INT >= 30) { - - android.view.WindowMetrics windowMetrics = wm.getCurrentWindowMetrics(); - android.graphics.Rect bounds = windowMetrics.getBounds(); - ret.x = bounds.width(); - ret.y = bounds.height(); - } else if (Build.VERSION.SDK_INT >= 13) { - - @SuppressWarnings("deprecation") - final Display defaultDisplay = wm.getDefaultDisplay(); - defaultDisplay.getSize(ret); - } else { - - @SuppressWarnings("deprecation") - final Display defaultDisplay = wm.getDefaultDisplay(); - ret.x = defaultDisplay.getWidth(); - ret.y = defaultDisplay.getHeight(); - } - return ret; - } - - - public static float convertDpToPixel(float dp, Context context) { - Resources resources = context.getResources(); - DisplayMetrics metrics = resources.getDisplayMetrics(); - float px = dp * (metrics.densityDpi / 160f); - return px; - } - - - public static float convertPixelsToDp(float px, Context context) { - Resources resources = context.getResources(); - DisplayMetrics metrics = resources.getDisplayMetrics(); - float dp = px / (metrics.densityDpi / 160f); - return dp; - } - - - - - public static float getDensity(Context context) { - float density = 0f; - if (context== null) { - return density; - } - try { - density = context.getResources().getDisplayMetrics().density; - } catch (Exception e) { - - } - return density; - } - - - public static boolean checkPix(Activity context, int width, int height) { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) { - DisplayMetrics metrics = new DisplayMetrics(); - context.getWindowManager().getDefaultDisplay().getRealMetrics(metrics); - return metrics.widthPixels == width && metrics.heightPixels == height; - } else { - return getScreenPixWidth(context) == width && getScreenPixHeight(context) == height; - } - } - - - public static int getScreenPixWidth(Context context) { - return context.getResources().getDisplayMetrics().widthPixels; - } - - - public static int getScreenPixHeight(Context context) { - return context.getResources().getDisplayMetrics().heightPixels; - } - - - public static int dipToPx(Context context, int dip) { - return (int) (dip * context.getResources().getDisplayMetrics().density + 0.5f); - } - - - public static int pxToDip(Context context, float pxValue) { - final float scale = context.getResources().getDisplayMetrics().density; - return (int) (pxValue / scale + 0.5f); - } - - - public static int sp2px(Context context, float spValue) { - final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; - return (int) (spValue * fontScale + 0.5f); - } - - - public static void hideInputMethod(View view) { - InputMethodManager imm = (InputMethodManager) view.getContext() - .getSystemService(Context.INPUT_METHOD_SERVICE); - if (imm != null) { - imm.hideSoftInputFromWindow(view.getWindowToken(), 0); - } - } - - - public static void showInputMethod(View view) { - InputMethodManager imm = (InputMethodManager) view.getContext() - .getSystemService(Context.INPUT_METHOD_SERVICE); - if (imm != null) { - imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT); - } - } - - - public static void showInputMethod(final View view, long delayMillis) { - - new Handler().postDelayed(new Runnable() { - - @Override - public void run() { - Resolution.showInputMethod(view); - - } - }, delayMillis); - } - - - public static boolean isScreenLocked(Context c) { - KeyguardManager mKeyguardManager = (KeyguardManager) c - .getSystemService(Context.KEYGUARD_SERVICE); - boolean bResult = !mKeyguardManager.inKeyguardRestrictedInputMode(); - - return bResult; - } - - public static int getBarHeight(Context context) { - Class c = null; - Object obj = null; - Field field = null; - int x = 0, sbar = 38; - - try { - c = Class.forName("com.android.internal.R$dimen"); - obj = c.newInstance(); - field = c.getField("status_bar_height"); - x = Integer.parseInt(field.get(obj).toString()); - sbar = context.getResources().getDimensionPixelSize(x); - } catch (Exception e1) { - e1.printStackTrace(); - } - return sbar; - } - - - - public static Point getNavigationBarSize(Context context) { - Point appUsableSize = getScreenSize(context, null); - Point realScreenSize = getRealScreenSize(context); - - - - - - - - if (appUsableSize.y < realScreenSize.y) { - return new Point(appUsableSize.x, realScreenSize.y - appUsableSize.y); - } - - - return new Point(); - } - - - public static Point getRealScreenSize(Context context) { - WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - Point size = new Point(); - - if (Build.VERSION.SDK_INT >= 30) { - - android.view.WindowMetrics windowMetrics = windowManager.getCurrentWindowMetrics(); - android.graphics.Rect bounds = windowMetrics.getBounds(); - size.x = bounds.width(); - size.y = bounds.height(); - } else if (Build.VERSION.SDK_INT >= 17) { - - @SuppressWarnings("deprecation") - Display display = windowManager.getDefaultDisplay(); - display.getRealSize(size); - } else if (Build.VERSION.SDK_INT >= 14) { - - @SuppressWarnings("deprecation") - Display display = windowManager.getDefaultDisplay(); - try { - size.x = (Integer) Display.class.getMethod("getRawWidth").invoke(display); - size.y = (Integer) Display.class.getMethod("getRawHeight").invoke(display); - } catch (Exception e) { - } - } - - return size; - } -} diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/ShortcutUtil.kt b/app/src/main/java/top/niunaijun/blackboxa/util/ShortcutUtil.kt deleted file mode 100644 index 51fe650..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/util/ShortcutUtil.kt +++ /dev/null @@ -1,77 +0,0 @@ -package top.niunaijun.blackboxa.util - -import android.content.Context -import android.content.Intent -import androidx.core.content.pm.ShortcutInfoCompat -import androidx.core.content.pm.ShortcutManagerCompat -import androidx.core.graphics.drawable.IconCompat -import androidx.core.graphics.drawable.toBitmap -import com.afollestad.materialdialogs.MaterialDialog -import com.afollestad.materialdialogs.input.input -import top.niunaijun.blackboxa.R -import top.niunaijun.blackboxa.app.App -import top.niunaijun.blackboxa.app.AppManager -import top.niunaijun.blackboxa.bean.AppInfo -import top.niunaijun.blackboxa.util.ContextUtil.openAppSystemSettings -import top.niunaijun.blackboxa.view.main.ShortcutActivity - - -object ShortcutUtil { - - - - fun createShortcut(context: Context,userID: Int, info: AppInfo) { - - if (ShortcutManagerCompat.isRequestPinShortcutSupported(context)) { - val labelName = info.name + userID - val intent = Intent(context, ShortcutActivity::class.java) - .setAction(Intent.ACTION_MAIN) - .putExtra("pkg", info.packageName) - .putExtra("userId", userID) - MaterialDialog(context).show { - title(res = R.string.app_shortcut) - input( - hintRes = R.string.shortcut_name, - prefill = labelName - ) { _, input -> - - val shortcutInfo: ShortcutInfoCompat = - ShortcutInfoCompat.Builder(context, info.packageName + userID) - .setIntent(intent) - .setShortLabel(input) - .setLongLabel(input) - .setIcon(IconCompat.createWithBitmap(info.icon!!.toBitmap())) - .build() - - ShortcutManagerCompat.requestPinShortcut(context, shortcutInfo, null) - showAllowPermissionDialog(context) - } - positiveButton(R.string.done) - negativeButton(R.string.cancel) - } - - } else { - toast(R.string.cannot_create_shortcut) - } - } - - private fun showAllowPermissionDialog(context: Context){ - if (!AppManager.mBlackBoxLoader.showShortcutPermissionDialog()){ - return - } - - MaterialDialog(context).show { - title(R.string.try_add_shortcut) - message(R.string.add_shortcut_fail_msg) - positiveButton(R.string.done) - negativeButton(R.string.permission_setting){ - App.getContext().openAppSystemSettings() - } - - neutralButton(R.string.no_reminders){ - AppManager.mBlackBoxLoader.invalidShortcutPermissionDialog(false) - } - } - - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/ToastEx.kt b/app/src/main/java/top/niunaijun/blackboxa/util/ToastEx.kt deleted file mode 100644 index 419f868..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/util/ToastEx.kt +++ /dev/null @@ -1,23 +0,0 @@ -package top.niunaijun.blackboxa.util - -import android.content.Context -import android.widget.Toast -import androidx.annotation.StringRes -import top.niunaijun.blackboxa.app.App - - -var toastImpl:Toast? = null - -fun Context.toast(msg:String){ - toastImpl?.cancel() - toastImpl = Toast.makeText(this,msg,Toast.LENGTH_SHORT) - toastImpl?.show() -} - -fun toast(msg: String){ - App.getContext().toast(msg) -} - -fun toast(@StringRes msgID:Int){ - toast(getString(msgID)) -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/ViewBindingEx.kt b/app/src/main/java/top/niunaijun/blackboxa/util/ViewBindingEx.kt deleted file mode 100644 index 9ffe5b7..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/util/ViewBindingEx.kt +++ /dev/null @@ -1,36 +0,0 @@ -package top.niunaijun.blackboxa.util - -import android.app.Activity -import android.app.Dialog -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.viewbinding.ViewBinding - - - -inline fun Activity.inflate(): Lazy = lazy { - inflateBinding(layoutInflater) -} - -inline fun Fragment.inflate(): Lazy = lazy { - inflateBinding(layoutInflater) -} - -inline fun Dialog.inflate(): Lazy = lazy { - inflateBinding(layoutInflater) -} - - -inline fun inflateBinding(layoutInflater: LayoutInflater): T { - val method = T::class.java.getMethod("inflate", LayoutInflater::class.java) - return method.invoke(null, layoutInflater) as T -} - -inline fun newBindingViewHolder(viewGroup: ViewGroup, attachToParent:Boolean = false): T { - val method = T::class.java.getMethod("inflate", - LayoutInflater::class.java, - ViewGroup::class.java, - Boolean::class.java) - return method.invoke(null,LayoutInflater.from(viewGroup.context),viewGroup,attachToParent) as T -} diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsAdapter.kt b/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsAdapter.kt deleted file mode 100644 index 4c1f0f0..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsAdapter.kt +++ /dev/null @@ -1,166 +0,0 @@ -package top.niunaijun.blackboxa.view.apps - -import android.graphics.drawable.Drawable -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import cbfg.rvadapter.RVHolder -import cbfg.rvadapter.RVHolderFactory -import top.niunaijun.blackboxa.R -import top.niunaijun.blackboxa.bean.AppInfo -import top.niunaijun.blackboxa.databinding.ItemAppBinding -import android.util.Log -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.drawable.BitmapDrawable -import android.graphics.drawable.ColorDrawable -import android.graphics.Color -import android.view.ViewTreeObserver -import androidx.recyclerview.widget.RecyclerView - - - -class AppsAdapter : RVHolderFactory() { - - companion object { - private const val TAG = "AppsAdapter" - private const val MAX_ICON_SIZE = 96 - private val DEFAULT_ICON_COLOR = Color.parseColor("#CCCCCC") - } - - override fun createViewHolder(parent: ViewGroup?, viewType: Int, item: Any): RVHolder { - return try { - AppsVH(inflate(R.layout.item_app, parent)) - } catch (e: Exception) { - Log.e(TAG, "Error creating ViewHolder: ${e.message}") - - FallbackAppsVH(inflate(R.layout.item_app, parent)) - } - } - - class AppsVH(itemView: View) : RVHolder(itemView) { - val binding = ItemAppBinding.bind(itemView) - private var currentIcon: Drawable? = null - private var isAttached = false - - init { - try { - - binding.icon.scaleType = ImageView.ScaleType.CENTER_CROP - - - itemView.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener { - override fun onPreDraw(): Boolean { - if (isAttached) { - itemView.viewTreeObserver.removeOnPreDrawListener(this) - } - return true - } - }) - } catch (e: Exception) { - Log.e(TAG, "Error initializing ViewHolder: ${e.message}") - } - } - - override fun setContent(item: AppInfo, isSelected: Boolean, payload: Any?) { - try { - - setIconSafely(item.icon, item.packageName) - - - binding.name.text = item.name ?: "Unknown App" - - - if (item.isXpModule) { - binding.cornerLabel.visibility = View.VISIBLE - } else { - binding.cornerLabel.visibility = View.INVISIBLE - } - - - isAttached = true - - } catch (e: Exception) { - Log.e(TAG, "Error setting content for ${item.packageName}: ${e.message}") - setSafeDefaults() - } - } - - private fun setIconSafely(icon: Drawable?, packageName: String) { - try { - if (icon != null) { - - val optimizedIcon = optimizeIcon(icon) - binding.icon.setImageDrawable(optimizedIcon) - currentIcon = optimizedIcon - } else { - - binding.icon.setImageDrawable(createDefaultIcon()) - currentIcon = null - } - } catch (e: Exception) { - Log.w(TAG, "Failed to set icon for $packageName: ${e.message}") - binding.icon.setImageDrawable(createDefaultIcon()) - currentIcon = null - } - } - - private fun optimizeIcon(icon: Drawable): Drawable { - return try { - - if (icon is BitmapDrawable) { - val bitmap = icon.bitmap - if (bitmap.width > MAX_ICON_SIZE || bitmap.height > MAX_ICON_SIZE) { - - val scaledBitmap = Bitmap.createScaledBitmap( - bitmap, MAX_ICON_SIZE, MAX_ICON_SIZE, true - ) - BitmapDrawable(itemView.resources, scaledBitmap) - } else { - icon - } - } else { - icon - } - } catch (e: Exception) { - Log.w(TAG, "Error optimizing icon: ${e.message}") - icon - } - } - - private fun createDefaultIcon(): Drawable { - return try { - ColorDrawable(DEFAULT_ICON_COLOR) - } catch (e: Exception) { - Log.w(TAG, "Error creating default icon: ${e.message}") - ColorDrawable(Color.GRAY) - } - } - - private fun setSafeDefaults() { - try { - binding.icon.setImageDrawable(createDefaultIcon()) - binding.name.text = "Unknown App" - binding.cornerLabel.visibility = View.INVISIBLE - } catch (e: Exception) { - Log.e(TAG, "Error setting safe defaults: ${e.message}") - } - } - } - - - class FallbackAppsVH(itemView: View) : RVHolder(itemView) { - val binding = ItemAppBinding.bind(itemView) - - override fun setContent(item: AppInfo, isSelected: Boolean, payload: Any?) { - try { - - binding.icon.setImageDrawable(ColorDrawable(DEFAULT_ICON_COLOR)) - binding.name.text = item.name ?: "Unknown App" - binding.cornerLabel.visibility = View.INVISIBLE - } catch (e: Exception) { - Log.e(TAG, "Error in fallback ViewHolder: ${e.message}") - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsFactory.kt b/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsFactory.kt deleted file mode 100644 index 037ddd3..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsFactory.kt +++ /dev/null @@ -1,14 +0,0 @@ -package top.niunaijun.blackboxa.view.apps - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import top.niunaijun.blackboxa.data.AppsRepository - - -@Suppress("UNCHECKED_CAST") -class AppsFactory(private val appsRepository: AppsRepository) : ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T { - return AppsViewModel(appsRepository) as T - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsFragment.kt b/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsFragment.kt deleted file mode 100644 index e4e5cd3..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsFragment.kt +++ /dev/null @@ -1,550 +0,0 @@ -package top.niunaijun.blackboxa.view.apps - -import android.graphics.Point -import android.os.Bundle -import android.text.TextUtils -import android.util.Log -import android.view.LayoutInflater -import android.view.MotionEvent -import android.view.View -import android.view.ViewGroup -import androidx.appcompat.widget.PopupMenu -import androidx.core.os.bundleOf -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.ItemTouchHelper -import androidx.recyclerview.widget.RecyclerView -import cbfg.rvadapter.RVAdapter -import com.afollestad.materialdialogs.MaterialDialog -import top.niunaijun.blackbox.BlackBoxCore -import top.niunaijun.blackboxa.R -import top.niunaijun.blackboxa.bean.AppInfo -import top.niunaijun.blackboxa.databinding.FragmentAppsBinding -import top.niunaijun.blackboxa.util.InjectionUtil -import top.niunaijun.blackboxa.util.ShortcutUtil -import top.niunaijun.blackboxa.util.inflate -import top.niunaijun.blackboxa.util.MemoryManager -import top.niunaijun.blackboxa.util.toast -import top.niunaijun.blackboxa.view.base.LoadingActivity -import top.niunaijun.blackboxa.view.main.MainActivity -import java.util.* -import kotlin.math.abs - - - -class AppsFragment : Fragment() { - - var userID: Int = 0 - - private lateinit var viewModel: AppsViewModel - - private lateinit var mAdapter: RVAdapter - - private val viewBinding: FragmentAppsBinding by inflate() - - private var popupMenu: PopupMenu? = null - - companion object { - private const val TAG = "AppsFragment" - - fun newInstance(userID:Int): AppsFragment { - val fragment = AppsFragment() - val bundle = bundleOf("userID" to userID) - fragment.arguments = bundle - return fragment - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - try { - super.onCreate(savedInstanceState) - viewModel = - ViewModelProvider(this, InjectionUtil.getAppsFactory()).get(AppsViewModel::class.java) - userID = requireArguments().getInt("userID", 0) - } catch (e: Exception) { - Log.e(TAG, "Error in onCreate: ${e.message}") - } - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - try { - viewBinding.stateView.showEmpty() - - mAdapter = - RVAdapter(requireContext(), AppsAdapter()).bind(viewBinding.recyclerView) - - viewBinding.recyclerView.adapter = mAdapter - - - val layoutManager = GridLayoutManager(requireContext(), 4) - layoutManager.isItemPrefetchEnabled = true - layoutManager.initialPrefetchItemCount = 8 - viewBinding.recyclerView.layoutManager = layoutManager - - - viewBinding.recyclerView.setItemViewCacheSize(20) - viewBinding.recyclerView.setHasFixedSize(true) - - - viewBinding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { - override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { - try { - super.onScrollStateChanged(recyclerView, newState) - when (newState) { - RecyclerView.SCROLL_STATE_IDLE -> { - - MemoryManager.optimizeMemoryForRecyclerView() - } - RecyclerView.SCROLL_STATE_DRAGGING -> { - - - } - RecyclerView.SCROLL_STATE_SETTLING -> { - - - } - } - } catch (e: Exception) { - Log.e(TAG, "Error in scroll state change: ${e.message}") - } - } - - override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { - try { - super.onScrolled(recyclerView, dx, dy) - - if (Math.abs(dy) > 100) { - - - - if (MemoryManager.isMemoryCritical()) { - Log.w(TAG, "Memory critical during fast scrolling, forcing GC") - MemoryManager.forceGarbageCollectionIfNeeded() - } - } - } catch (e: Exception) { - Log.e(TAG, "Error in scroll: ${e.message}") - } - } - }) - - val touchCallBack = AppsTouchCallBack { from, to -> - try { - onItemMove(from, to) - viewModel.updateSortLiveData.postValue(true) - } catch (e: Exception) { - Log.e(TAG, "Error in touch callback: ${e.message}") - } - } - - val itemTouchHelper = ItemTouchHelper(touchCallBack) - itemTouchHelper.attachToRecyclerView(viewBinding.recyclerView) - - mAdapter.setItemClickListener { _, data, _ -> - try { - showLoading() - viewModel.launchApk(data.packageName, userID) - } catch (e: Exception) { - Log.e(TAG, "Error launching app: ${e.message}") - hideLoading() - } - } - - interceptTouch() - setOnLongClick() - return viewBinding.root - } catch (e: Exception) { - Log.e(TAG, "Error in onCreateView: ${e.message}") - - return View(requireContext()) - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - try { - super.onViewCreated(view, savedInstanceState) - initData() - } catch (e: Exception) { - Log.e(TAG, "Error in onViewCreated: ${e.message}") - } - } - - override fun onStart() { - try { - super.onStart() - - - try { - BlackBoxCore.get().addServiceAvailableCallback { - Log.d(TAG, "Services became available, refreshing app list") - - viewModel.getInstalledAppsWithRetry(userID) - } - } catch (e: Exception) { - Log.e(TAG, "Error registering service available callback: ${e.message}") - } - - viewModel.getInstalledAppsWithRetry(userID) - } catch (e: Exception) { - Log.e(TAG, "Error in onStart: ${e.message}") - } - } - - - private fun interceptTouch() { - try { - val point = Point() - var isScrolling = false - var scrollStartTime = 0L - - viewBinding.recyclerView.setOnTouchListener { _, e -> - try { - when (e.action) { - MotionEvent.ACTION_DOWN -> { - - isScrolling = false - scrollStartTime = System.currentTimeMillis() - point.set(0, 0) - } - - MotionEvent.ACTION_UP -> { - val scrollDuration = System.currentTimeMillis() - scrollStartTime - - - if (!isScrolling && !isMove(point, e) && scrollDuration < 500) { - try { - popupMenu?.show() - } catch (e: Exception) { - Log.e(TAG, "Error showing popup menu: ${e.message}") - } - } - - popupMenu = null - point.set(0, 0) - isScrolling = false - } - - MotionEvent.ACTION_MOVE -> { - if (point.x == 0 && point.y == 0) { - point.x = e.rawX.toInt() - point.y = e.rawY.toInt() - } - - - if (isMove(point, e)) { - isScrolling = true - popupMenu?.dismiss() - } - - - isDownAndUp(point, e) - } - } - } catch (e: Exception) { - Log.e(TAG, "Error in touch listener: ${e.message}") - } - return@setOnTouchListener false - } - } catch (e: Exception) { - Log.e(TAG, "Error in interceptTouch: ${e.message}") - } - } - - private fun isMove(point: Point, e: MotionEvent): Boolean { - return try { - val max = 40 - - val x = point.x - val y = point.y - - val xU = abs(x - e.rawX) - val yU = abs(y - e.rawY) - xU > max || yU > max - } catch (e: Exception) { - Log.e(TAG, "Error in isMove: ${e.message}") - false - } - } - - private fun isDownAndUp(point: Point, e: MotionEvent) { - try { - val min = 10 - val y = point.y - val yU = y - e.rawY - - if (abs(yU) > min) { - try { - (requireActivity() as? MainActivity)?.showFloatButton(yU < 0) - } catch (e: Exception) { - Log.e(TAG, "Error showing/hiding float button: ${e.message}") - } - } - } catch (e: Exception) { - Log.e(TAG, "Error in isDownAndUp: ${e.message}") - } - } - - private fun onItemMove(fromPosition: Int, toPosition: Int) { - try { - - val items = mAdapter.getItems() - if (fromPosition < 0 || toPosition < 0 || - fromPosition >= items.size || toPosition >= items.size) { - Log.w(TAG, "Invalid positions for move: from=$fromPosition, to=$toPosition, size=${items.size}") - return - } - - if (fromPosition < toPosition) { - for (i in fromPosition until toPosition) { - try { - Collections.swap(items, i, i + 1) - } catch (e: Exception) { - Log.e(TAG, "Error swapping items at position $i: ${e.message}") - return - } - } - } else { - for (i in fromPosition downTo toPosition + 1) { - try { - Collections.swap(items, i, i - 1) - } catch (e: Exception) { - Log.e(TAG, "Error swapping items at position $i: ${e.message}") - return - } - } - } - - try { - mAdapter.notifyItemMoved(fromPosition, toPosition) - } catch (e: Exception) { - Log.e(TAG, "Error notifying item moved: ${e.message}") - - mAdapter.notifyDataSetChanged() - } - } catch (e: Exception) { - Log.e(TAG, "Error in onItemMove: ${e.message}") - } - } - - private fun setOnLongClick() { - try { - mAdapter.setItemLongClickListener { view, data, _ -> - try { - popupMenu = PopupMenu(requireContext(),view).also { - it.inflate(R.menu.app_menu) - it.setOnMenuItemClickListener { item -> - try { - when (item.itemId) { - R.id.app_remove -> { - if (data.isXpModule) { - toast(R.string.uninstall_module_toast) - } else { - unInstallApk(data) - } - } - - R.id.app_clear -> { - clearApk(data) - } - - R.id.app_stop -> { - stopApk(data) - } - - R.id.app_shortcut -> { - ShortcutUtil.createShortcut(requireContext(), userID, data) - } - } - return@setOnMenuItemClickListener true - } catch (e: Exception) { - Log.e(TAG, "Error in menu item click: ${e.message}") - return@setOnMenuItemClickListener false - } - } - it.show() - } - } catch (e: Exception) { - Log.e(TAG, "Error in long click: ${e.message}") - } - } - } catch (e: Exception) { - Log.e(TAG, "Error in setOnLongClick: ${e.message}") - } - } - - private fun initData() { - try { - viewBinding.stateView.showLoading() - viewModel.getInstalledApps(userID) - viewModel.appsLiveData.observe(viewLifecycleOwner) { - try { - if (it != null) { - mAdapter.setItems(it) - if (it.isEmpty()) { - viewBinding.stateView.showEmpty() - } else { - viewBinding.stateView.showContent() - } - } - } catch (e: Exception) { - Log.e(TAG, "Error observing apps data: ${e.message}") - } - } - - viewModel.resultLiveData.observe(viewLifecycleOwner) { - try { - if (!TextUtils.isEmpty(it)) { - hideLoading() - requireContext().toast(it) - viewModel.getInstalledApps(userID) - scanUser() - } - } catch (e: Exception) { - Log.e(TAG, "Error observing result data: ${e.message}") - } - } - - viewModel.launchLiveData.observe(viewLifecycleOwner) { - try { - it?.run { - hideLoading() - if (!it) { - toast(R.string.start_fail) - } - } - } catch (e: Exception) { - Log.e(TAG, "Error observing launch data: ${e.message}") - } - } - - viewModel.updateSortLiveData.observe(viewLifecycleOwner) { - try { - if (this::mAdapter.isInitialized) { - viewModel.updateApkOrder(userID, mAdapter.getItems()) - } - } catch (e: Exception) { - Log.e(TAG, "Error observing sort data: ${e.message}") - } - } - } catch (e: Exception) { - Log.e(TAG, "Error in initData: ${e.message}") - } - } - - override fun onStop() { - try { - super.onStop() - viewModel.resultLiveData.value = null - viewModel.launchLiveData.value = null - } catch (e: Exception) { - Log.e(TAG, "Error in onStop: ${e.message}") - } - } - - private fun unInstallApk(info: AppInfo) { - try { - MaterialDialog(requireContext()).show { - title(R.string.uninstall_app) - message(text = getString(R.string.uninstall_app_hint, info.name)) - positiveButton(R.string.done) { - try { - showLoading() - viewModel.unInstall(info.packageName, userID) - } catch (e: Exception) { - Log.e(TAG, "Error uninstalling app: ${e.message}") - hideLoading() - } - } - negativeButton(R.string.cancel) - } - } catch (e: Exception) { - Log.e(TAG, "Error showing uninstall dialog: ${e.message}") - } - } - - - private fun stopApk(info: AppInfo) { - try { - MaterialDialog(requireContext()).show { - title(R.string.app_stop) - message(text = getString(R.string.app_stop_hint,info.name)) - positiveButton(R.string.done) { - try { - BlackBoxCore.get().stopPackage(info.packageName, userID) - toast(getString(R.string.is_stop,info.name)) - } catch (e: Exception) { - Log.e(TAG, "Error stopping app: ${e.message}") - } - } - negativeButton(R.string.cancel) - } - } catch (e: Exception) { - Log.e(TAG, "Error showing stop dialog: ${e.message}") - } - } - - - private fun clearApk(info: AppInfo) { - try { - MaterialDialog(requireContext()).show { - title(R.string.app_clear) - message(text = getString(R.string.app_clear_hint,info.name)) - positiveButton(R.string.done) { - try { - showLoading() - viewModel.clearApkData(info.packageName, userID) - } catch (e: Exception) { - Log.e(TAG, "Error clearing app data: ${e.message}") - hideLoading() - } - } - negativeButton(R.string.cancel) - } - } catch (e: Exception) { - Log.e(TAG, "Error showing clear dialog: ${e.message}") - } - } - - fun installApk(source: String) { - try { - showLoading() - viewModel.install(source, userID) - } catch (e: Exception) { - Log.e(TAG, "Error installing APK: ${e.message}") - hideLoading() - } - } - - private fun scanUser() { - try { - (requireActivity() as? MainActivity)?.scanUser() - } catch (e: Exception) { - Log.e(TAG, "Error scanning user: ${e.message}") - } - } - - private fun showLoading() { - try { - if(requireActivity() is LoadingActivity){ - (requireActivity() as LoadingActivity).showLoading() - } - } catch (e: Exception) { - Log.e(TAG, "Error showing loading: ${e.message}") - } - } - - private fun hideLoading() { - try { - if(requireActivity() is LoadingActivity){ - (requireActivity() as LoadingActivity).hideLoading() - } - } catch (e: Exception) { - Log.e(TAG, "Error hiding loading: ${e.message}") - } - } -} diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsTouchCallBack.kt b/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsTouchCallBack.kt deleted file mode 100644 index 5a72342..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsTouchCallBack.kt +++ /dev/null @@ -1,105 +0,0 @@ -package top.niunaijun.blackboxa.view.apps - -import androidx.recyclerview.widget.ItemTouchHelper -import androidx.recyclerview.widget.RecyclerView -import android.util.Log - -class AppsTouchCallBack(private val onMoveBlock: (from: Int, to: Int) -> Unit) : - ItemTouchHelper.Callback() { - - companion object { - private const val TAG = "AppsTouchCallBack" - } - - override fun getMovementFlags( - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder - ): Int { - return try { - makeMovementFlags( - ItemTouchHelper.UP or ItemTouchHelper.DOWN or - ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT, - 0 - ) - } catch (e: Exception) { - Log.e(TAG, "Error getting movement flags: ${e.message}") - - makeMovementFlags(0, 0) - } - } - - override fun onMove( - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - target: RecyclerView.ViewHolder - ): Boolean { - return try { - val fromPosition = viewHolder.bindingAdapterPosition - val toPosition = target.bindingAdapterPosition - - - if (fromPosition == RecyclerView.NO_POSITION || toPosition == RecyclerView.NO_POSITION) { - Log.w(TAG, "Invalid positions: from=$fromPosition, to=$toPosition") - false - } else if (fromPosition == toPosition) { - - false - } else { - - onMoveBlock(fromPosition, toPosition) - true - } - } catch (e: Exception) { - Log.e(TAG, "Error in onMove: ${e.message}") - false - } - } - - override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - - } - - override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) { - try { - super.onSelectedChanged(viewHolder, actionState) - - when (actionState) { - ItemTouchHelper.ACTION_STATE_DRAG -> { - - viewHolder?.itemView?.alpha = 0.8f - } - ItemTouchHelper.ACTION_STATE_IDLE -> { - - viewHolder?.itemView?.alpha = 1.0f - } - } - } catch (e: Exception) { - Log.e(TAG, "Error in onSelectedChanged: ${e.message}") - } - } - - override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) { - try { - super.clearView(recyclerView, viewHolder) - - viewHolder.itemView.alpha = 1.0f - } catch (e: Exception) { - Log.e(TAG, "Error in clearView: ${e.message}") - } - } - - override fun canDropOver( - recyclerView: RecyclerView, - current: RecyclerView.ViewHolder, - target: RecyclerView.ViewHolder - ): Boolean { - return try { - - val targetPosition = target.bindingAdapterPosition - targetPosition != RecyclerView.NO_POSITION - } catch (e: Exception) { - Log.e(TAG, "Error in canDropOver: ${e.message}") - false - } - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsViewModel.kt b/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsViewModel.kt deleted file mode 100644 index 14d2c99..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsViewModel.kt +++ /dev/null @@ -1,81 +0,0 @@ -package top.niunaijun.blackboxa.view.apps - -import androidx.lifecycle.MutableLiveData -import top.niunaijun.blackboxa.bean.AppInfo -import top.niunaijun.blackboxa.data.AppsRepository -import top.niunaijun.blackboxa.view.base.BaseViewModel -import android.util.Log - - -class AppsViewModel(private val repo: AppsRepository) : BaseViewModel() { - - val appsLiveData = MutableLiveData>() - - val resultLiveData = MutableLiveData() - - val launchLiveData = MutableLiveData() - - - val updateSortLiveData = MutableLiveData() - - fun getInstalledApps(userId: Int) { - launchOnUI { - repo.getVmInstallList(userId, appsLiveData) - } - } - - - fun getInstalledAppsWithRetry(userId: Int, maxRetries: Int = 3) { - var retryCount = 0 - - fun attemptLoad() { - launchOnUI { - repo.getVmInstallList(userId, appsLiveData) - - - val currentApps = appsLiveData.value - if ((currentApps == null || currentApps.isEmpty()) && retryCount < maxRetries) { - retryCount++ - Log.d("AppsViewModel", "No apps loaded, retrying... (${retryCount}/${maxRetries})") - - - android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({ - attemptLoad() - }, 1000) - } - } - } - - attemptLoad() - } - - fun install(source: String, userID: Int) { - launchOnUI { - repo.installApk(source, userID, resultLiveData) - } - } - - fun unInstall(packageName: String, userID: Int) { - launchOnUI { - repo.unInstall(packageName, userID, resultLiveData) - } - } - - fun clearApkData(packageName: String,userID: Int){ - launchOnUI { - repo.clearApkData(packageName,userID,resultLiveData) - } - } - - fun launchApk(packageName: String, userID: Int) { - launchOnUI { - repo.launchApk(packageName, userID, launchLiveData) - } - } - - fun updateApkOrder(userID: Int,dataList:List){ - launchOnUI { - repo.updateApkOrder(userID,dataList) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/base/BaseActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/base/BaseActivity.kt deleted file mode 100644 index d27d14f..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/base/BaseActivity.kt +++ /dev/null @@ -1,28 +0,0 @@ -package top.niunaijun.blackboxa.view.base - -import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.Toolbar - - -open class BaseActivity : AppCompatActivity() { - - protected fun initToolbar(toolbar: Toolbar,title:Int, showBack: Boolean = false, onBack: (() -> Unit)? = null) { - setSupportActionBar(toolbar) - toolbar.setTitle(title) - if (showBack) { - supportActionBar?.let { - it.setDisplayHomeAsUpEnabled(true) - toolbar.setNavigationOnClickListener { - if (onBack != null) { - onBack() - } - finish() - } - } - } - } - - protected fun currentUserID():Int{ - return intent.getIntExtra("userID", 0) - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/base/BaseViewModel.kt b/app/src/main/java/top/niunaijun/blackboxa/view/base/BaseViewModel.kt deleted file mode 100644 index a31a005..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/base/BaseViewModel.kt +++ /dev/null @@ -1,29 +0,0 @@ -package top.niunaijun.blackboxa.view.base - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.* - - -open class BaseViewModel : ViewModel() { - - fun launchOnUI(block: suspend CoroutineScope.() -> Unit) { - viewModelScope.launch { - withContext(Dispatchers.IO) { - try { - block() - } catch (e: Throwable) { - e.printStackTrace() - } - - } - } - } - - - override fun onCleared() { - super.onCleared() - viewModelScope.cancel() - } - -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/base/LoadingActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/base/LoadingActivity.kt deleted file mode 100644 index 9ea43fc..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/base/LoadingActivity.kt +++ /dev/null @@ -1,38 +0,0 @@ -package top.niunaijun.blackboxa.view.base - -import android.view.KeyEvent -import com.roger.catloadinglibrary.CatLoadingView -import top.niunaijun.blackboxa.R - - -abstract class LoadingActivity : BaseActivity() { - - private lateinit var loadingView: CatLoadingView - - - fun showLoading() { - if (!this::loadingView.isInitialized) { - loadingView = CatLoadingView() - } - - if (!loadingView.isAdded) { - loadingView.setBackgroundColor(R.color.primary) - loadingView.show(supportFragmentManager, "") - supportFragmentManager.executePendingTransactions() - loadingView.setClickCancelAble(false) - loadingView.dialog?.setOnKeyListener { _, keyCode, _ -> - if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) { - return@setOnKeyListener true - } - false - } - } - } - - - fun hideLoading() { - if (this::loadingView.isInitialized) { - loadingView.dismiss() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationAdapter.kt b/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationAdapter.kt deleted file mode 100644 index 8e4bc24..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationAdapter.kt +++ /dev/null @@ -1,38 +0,0 @@ -package top.niunaijun.blackboxa.view.fake - -import android.view.View -import android.view.ViewGroup -import cbfg.rvadapter.RVHolder -import cbfg.rvadapter.RVHolderFactory -import top.niunaijun.blackbox.fake.frameworks.BLocationManager -import top.niunaijun.blackboxa.R -import top.niunaijun.blackboxa.bean.FakeLocationBean -import top.niunaijun.blackboxa.databinding.ItemFakeBinding -import top.niunaijun.blackboxa.util.getString - - - -class FakeLocationAdapter : RVHolderFactory() { - - override fun createViewHolder(parent: ViewGroup?, viewType: Int, item: Any): RVHolder { - return FakeLocationVH(inflate(R.layout.item_fake,parent)) - } - - class FakeLocationVH(itemView:View):RVHolder(itemView){ - - private val binding = ItemFakeBinding.bind(itemView) - - override fun setContent(item: FakeLocationBean, isSelected: Boolean, payload: Any?) { - binding.icon.setImageDrawable(item.icon) - binding.name.text = item.name - if (item.fakeLocation == null || item.fakeLocationPattern == BLocationManager.CLOSE_MODE) { - binding.fakeLocation.text = getString(R.string.real_location) - } else { - binding.fakeLocation.text = - String.format("%f, %f", item.fakeLocation!!.latitude, item.fakeLocation!!.longitude) - } - binding.cornerLabel.visibility = View.VISIBLE - - } - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationFactory.kt b/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationFactory.kt deleted file mode 100644 index a9e0211..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationFactory.kt +++ /dev/null @@ -1,14 +0,0 @@ -package top.niunaijun.blackboxa.view.fake - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import top.niunaijun.blackboxa.data.FakeLocationRepository - - -class FakeLocationFactory(private val repo: FakeLocationRepository) : - ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T { - return FakeLocationViewModel(repo) as T - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationViewModel.kt b/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationViewModel.kt deleted file mode 100644 index f35534e..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationViewModel.kt +++ /dev/null @@ -1,33 +0,0 @@ -package top.niunaijun.blackboxa.view.fake - -import androidx.lifecycle.MutableLiveData -import top.niunaijun.blackbox.entity.location.BLocation -import top.niunaijun.blackboxa.bean.FakeLocationBean -import top.niunaijun.blackboxa.data.FakeLocationRepository -import top.niunaijun.blackboxa.view.base.BaseViewModel - - -class FakeLocationViewModel(private val mRepo: FakeLocationRepository) : BaseViewModel() { - - val appsLiveData = MutableLiveData>() - - - fun getInstallAppList(userID: Int) { - launchOnUI { - mRepo.getInstalledAppList(userID, appsLiveData) - } - } - - fun setPattern(userId: Int, pkg: String, pattern: Int) { - launchOnUI { - mRepo.setPattern(userId, pkg, pattern) - } - } - - fun setLocation(userId: Int, pkg: String, location: BLocation) { - launchOnUI { - mRepo.setLocation(userId, pkg, location) - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeManagerActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeManagerActivity.kt deleted file mode 100644 index 377ea30..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeManagerActivity.kt +++ /dev/null @@ -1,184 +0,0 @@ -package top.niunaijun.blackboxa.view.fake - -import android.app.Activity -import android.content.Context -import android.content.Intent -import android.os.Bundle -import android.view.Menu -import android.view.inputmethod.InputMethodManager -import androidx.activity.result.contract.ActivityResultContracts -import androidx.lifecycle.ViewModelProvider -import androidx.recyclerview.widget.LinearLayoutManager -import cbfg.rvadapter.RVAdapter -import com.afollestad.materialdialogs.MaterialDialog -import com.ferfalk.simplesearchview.SimpleSearchView -import top.niunaijun.blackbox.entity.location.BLocation -import top.niunaijun.blackbox.fake.frameworks.BLocationManager -import top.niunaijun.blackboxa.R -import top.niunaijun.blackboxa.bean.FakeLocationBean -import top.niunaijun.blackboxa.databinding.ActivityListBinding -import top.niunaijun.blackboxa.util.InjectionUtil -import top.niunaijun.blackboxa.util.inflate -import top.niunaijun.blackboxa.util.toast -import top.niunaijun.blackboxa.view.base.BaseActivity - - -class FakeManagerActivity : BaseActivity() { - val TAG: String = "FakeManagerActivity" - - private val viewBinding: ActivityListBinding by inflate() - - - private lateinit var mAdapter: RVAdapter - - private lateinit var viewModel: FakeLocationViewModel - - private var appList: List = ArrayList() - - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(viewBinding.root) - - initToolbar(viewBinding.toolbarLayout.toolbar, R.string.fake_location, true) - - mAdapter = RVAdapter(this,FakeLocationAdapter()).bind(viewBinding.recyclerView) - .setItemClickListener { _, data, _ -> - - val intent = Intent(this, FollowMyLocationOverlay::class.java) - intent.putExtra("location", data.fakeLocation) - intent.putExtra("pkg", data.packageName) - - locationResult.launch(intent) - }.setItemLongClickListener { _, item, position -> - disableFakeLocation(item,position) - } - - viewBinding.recyclerView.layoutManager = LinearLayoutManager(this) - - - initSearchView() - initViewModel() - } - - private fun disableFakeLocation(item: FakeLocationBean,position:Int) { - MaterialDialog(this).show { - title(R.string.close_fake_location) - message(text = getString(R.string.close_app_fake_location,item.name)) - negativeButton(R.string.cancel) - positiveButton(R.string.done){ - BLocationManager.disableFakeLocation(currentUserID(),item.packageName) - toast(getString(R.string.close_fake_location_success,item.name)) - item.fakeLocationPattern = BLocationManager.CLOSE_MODE - mAdapter.replaceAt(position,item) - } - } - } - - private fun initSearchView() { - viewBinding.searchView.setOnQueryTextListener(object : - SimpleSearchView.OnQueryTextListener { - override fun onQueryTextChange(newText: String): Boolean { - filterApp(newText) - return true - } - - override fun onQueryTextCleared(): Boolean { - return true - } - - override fun onQueryTextSubmit(query: String): Boolean { - return true - } - - }) - } - - private fun initViewModel() { - viewModel = ViewModelProvider(this, InjectionUtil.getFakeLocationFactory()).get( - FakeLocationViewModel::class.java - ) - loadAppList() - viewBinding.toolbarLayout.toolbar.setTitle(R.string.fake_location) - - viewModel.appsLiveData.observe(this) { - if (it != null) { - this.appList = it - viewBinding.searchView.setQuery("", false) - filterApp("") - if (it.isNotEmpty()) { - viewBinding.stateView.showContent() - } else { - viewBinding.stateView.showEmpty() - } - } - } - } - - private fun loadAppList() { - viewBinding.stateView.showLoading() - viewModel.getInstallAppList(currentUserID()) - } - - private val locationResult = - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode == RESULT_OK) { - - it.data?.let { data -> - val latitude = data.getDoubleExtra("latitude", 0.0) - val longitude = data.getDoubleExtra("longitude", 0.0) - val pkg = data.getStringExtra("pkg") - - viewModel.setPattern(currentUserID(), pkg.toString(), BLocationManager.OWN_MODE) - viewModel.setLocation(currentUserID(), pkg.toString(), BLocation(latitude, longitude)) - - toast(getString(R.string.set_location,latitude.toString(), longitude.toString())) - - loadAppList() - } - - } - } - - - private fun filterApp(newText: String) { - val newList = this.appList.filter { - it.name.contains(newText, true) or it.packageName.contains(newText, true) - } - mAdapter.setItems(newList) - } - - private fun finishWithResult(source: String) { - intent.putExtra("source", source) - setResult(Activity.RESULT_OK, intent) - val imm: InputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager - window.peekDecorView()?.run { - imm.hideSoftInputFromWindow(windowToken, 0) - } - finish() - } - - - override fun onBackPressed() { - if (viewBinding.searchView.isSearchOpen) { - viewBinding.searchView.closeSearch() - } else { - super.onBackPressed() - } - } - - override fun onCreateOptionsMenu(menu: Menu?): Boolean { - menuInflater.inflate(R.menu.menu_search, menu) - val item = menu!!.findItem(R.id.list_search) - viewBinding.searchView.setMenuItem(item) - return true - } - - - companion object { - fun start(context: Context) { - val intent = Intent(context, FakeManagerActivity::class.java) - context.startActivity(intent) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FollowMyLocationOverlay.kt b/app/src/main/java/top/niunaijun/blackboxa/view/fake/FollowMyLocationOverlay.kt deleted file mode 100644 index d532b3f..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FollowMyLocationOverlay.kt +++ /dev/null @@ -1,139 +0,0 @@ -package top.niunaijun.blackboxa.view.fake - - -import android.app.Activity -import android.os.Bundle -import android.view.inputmethod.InputMethodManager -import androidx.appcompat.app.AppCompatActivity -import androidx.core.app.ActivityCompat -import androidx.preference.PreferenceManager -import org.osmdroid.config.Configuration -import org.osmdroid.events.MapEventsReceiver -import org.osmdroid.tileprovider.tilesource.TileSourceFactory -import org.osmdroid.util.GeoPoint -import org.osmdroid.views.overlay.MapEventsOverlay -import org.osmdroid.views.overlay.Marker -import top.niunaijun.blackbox.entity.location.BLocation -import top.niunaijun.blackboxa.databinding.ActivityOsmdroidBinding -import top.niunaijun.blackboxa.util.inflate -import top.niunaijun.blackboxa.util.toast - - - -class FollowMyLocationOverlay : AppCompatActivity() { - val TAG: String = "FollowMyLocationOverlay" - - private val REQUEST_PERMISSIONS_REQUEST_CODE = 1 - - private val binding: ActivityOsmdroidBinding by inflate() - - lateinit var startPoint: GeoPoint - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - - - - - Configuration.getInstance().load(this, PreferenceManager.getDefaultSharedPreferences(this)) - - - - - - - - - setContentView(binding.root) - - val location: BLocation? = intent.getParcelableExtra("location") - - startPoint = if (location == null) { - GeoPoint(30.2736, 120.1563) - } else { - GeoPoint(location.latitude, location.longitude) - } - - - val startMarker = Marker(binding.map) - startMarker.position = startPoint - startMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM) - - binding.map.overlays.add(startMarker) - val mReceive: MapEventsReceiver = object : MapEventsReceiver { - override fun singleTapConfirmedHelper(p: GeoPoint): Boolean { - startPoint = p - startMarker.position = p - startMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM) - binding.map.overlays.add(startMarker) - toast(p.latitude.toString() + " - " + p.longitude) - return false - } - - override fun longPressHelper(p: GeoPoint): Boolean { - return false - } - } - binding.map.overlays.add(MapEventsOverlay(mReceive)) - val mapController = binding.map.controller - mapController.setZoom(12.5) - - mapController.setCenter(startPoint) - binding.map.setTileSource(TileSourceFactory.MAPNIK) - } - - override fun onBackPressed() { - finishWithResult(startPoint) - } - - override fun onResume() { - super.onResume() - - - - - binding.map.onResume() - } - - override fun onPause() { - super.onPause() - - - - - binding.map.onPause() - } - - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray - ) { - val permissionsToRequest = ArrayList() - var i = 0 - while (i < grantResults.size) { - permissionsToRequest.add(permissions[i]) - i++ - } - if (permissionsToRequest.size > 0) { - ActivityCompat.requestPermissions( - this, - permissionsToRequest.toTypedArray(), - REQUEST_PERMISSIONS_REQUEST_CODE - ) - } - } - - private fun finishWithResult(geoPoint: GeoPoint) { - intent.putExtra("latitude", geoPoint.latitude) - intent.putExtra("longitude", geoPoint.longitude) - setResult(Activity.RESULT_OK, intent) - val imm: InputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager - window.peekDecorView()?.run { - imm.hideSoftInputFromWindow(windowToken, 0) - } - finish() - } - -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsAdapter.kt b/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsAdapter.kt deleted file mode 100644 index 28bbcab..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsAdapter.kt +++ /dev/null @@ -1,32 +0,0 @@ -package top.niunaijun.blackboxa.view.gms - -import android.view.View -import android.view.ViewGroup -import cbfg.rvadapter.RVHolder -import cbfg.rvadapter.RVHolderFactory -import top.niunaijun.blackboxa.R -import top.niunaijun.blackboxa.bean.GmsBean -import top.niunaijun.blackboxa.databinding.ItemGmsBinding - - -class GmsAdapter : RVHolderFactory() { - - override fun createViewHolder(parent: ViewGroup?, viewType: Int, item: Any): RVHolder { - return GmsVH(inflate(R.layout.item_gms,parent)) - } - - - class GmsVH(itemView:View):RVHolder(itemView){ - - private val binding = ItemGmsBinding.bind(itemView) - override fun setContent(item: GmsBean, isSelected: Boolean, payload: Any?) { - binding.tvTitle.text = item.userName - binding.checkbox.isChecked = item.isInstalledGms - binding.checkbox.setOnCheckedChangeListener { buttonView, _ -> - if(buttonView.isPressed){ - binding.root.performClick() - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsFactory.kt b/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsFactory.kt deleted file mode 100644 index 24c27d2..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsFactory.kt +++ /dev/null @@ -1,13 +0,0 @@ -package top.niunaijun.blackboxa.view.gms - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import top.niunaijun.blackboxa.data.GmsRepository - - -class GmsFactory(private val repo:GmsRepository): ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T { - return GmsViewModel(repo) as T - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsManagerActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsManagerActivity.kt deleted file mode 100644 index b7d1255..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsManagerActivity.kt +++ /dev/null @@ -1,128 +0,0 @@ -package top.niunaijun.blackboxa.view.gms - -import android.content.Context -import android.content.Intent -import android.os.Bundle -import android.widget.Switch -import androidx.lifecycle.ViewModelProvider -import androidx.recyclerview.widget.LinearLayoutManager -import cbfg.rvadapter.RVAdapter -import com.afollestad.materialdialogs.MaterialDialog -import top.niunaijun.blackboxa.R -import top.niunaijun.blackboxa.bean.GmsBean -import top.niunaijun.blackboxa.databinding.ActivityGmsBinding -import top.niunaijun.blackboxa.util.InjectionUtil -import top.niunaijun.blackboxa.util.inflate -import top.niunaijun.blackboxa.util.toast -import top.niunaijun.blackboxa.view.base.LoadingActivity - - -class GmsManagerActivity : LoadingActivity() { - - private lateinit var viewModel: GmsViewModel - - private lateinit var mAdapter: RVAdapter - - private val viewBinding: ActivityGmsBinding by inflate() - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(viewBinding.root) - initToolbar(viewBinding.toolbarLayout.toolbar, R.string.gms_manager, true) - initViewModel() - - initRecyclerView() - } - - private fun initViewModel() { - viewModel = ViewModelProvider(this, InjectionUtil.getGmsFactory())[GmsViewModel::class.java] - showLoading() - - viewModel.mInstalledLiveData.observe(this) { - hideLoading() - mAdapter.setItems(it) - } - - viewModel.mUpdateInstalledLiveData.observe(this) { result -> - if (result == null) { - return@observe - } - - val items = mAdapter.getItems() - for (index in items.indices) { - val bean = items[index] - if (bean.userID == result.userID) { - if (result.success) { - bean.isInstalledGms = !bean.isInstalledGms - } - mAdapter.replaceAt( index,bean) - break - } - } - - hideLoading() - - if (result.success) { - toast(result.msg) - } else { - MaterialDialog(this).show { - title(R.string.gms_manager) - message(text = result.msg) - positiveButton(R.string.done) - } - } - } - - viewModel.getInstalledUser() - } - - private fun initRecyclerView() { - mAdapter = RVAdapter(this, GmsAdapter()).bind(viewBinding.recyclerView) - .setItemClickListener { view, item, _ -> - val checkbox = view.findViewById(R.id.checkbox) - if (item.isInstalledGms) { - uninstallGms(item.userID, checkbox) - } else { - installGms(item.userID, checkbox) - } - } - viewBinding.recyclerView.layoutManager = LinearLayoutManager(this) - - } - - private fun installGms(userID: Int, checkbox: Switch){ - MaterialDialog(this).show { - title(R.string.enable_gms) - message(R.string.enable_gms_hint) - positiveButton(R.string.done){ - showLoading() - viewModel.installGms(userID) - } - negativeButton(R.string.cancel){ - checkbox.isChecked = !checkbox.isChecked - } - } - } - - private fun uninstallGms(userID: Int, checkbox: Switch){ - MaterialDialog(this).show { - title(R.string.disable_gms) - message(R.string.disable_gms_hint) - positiveButton(R.string.done){ - showLoading() - viewModel.uninstallGms(userID) - } - negativeButton(R.string.cancel){ - checkbox.isChecked = !checkbox.isChecked - } - } - } - - - companion object{ - fun start(context: Context){ - val intent = Intent(context,GmsManagerActivity::class.java) - context.startActivity(intent) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsViewModel.kt b/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsViewModel.kt deleted file mode 100644 index 28289e7..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsViewModel.kt +++ /dev/null @@ -1,33 +0,0 @@ -package top.niunaijun.blackboxa.view.gms - -import androidx.lifecycle.MutableLiveData -import top.niunaijun.blackboxa.bean.GmsBean -import top.niunaijun.blackboxa.bean.GmsInstallBean -import top.niunaijun.blackboxa.data.GmsRepository -import top.niunaijun.blackboxa.view.base.BaseViewModel - - -class GmsViewModel(private val mRepo: GmsRepository) : BaseViewModel() { - - val mInstalledLiveData = MutableLiveData>() - - val mUpdateInstalledLiveData = MutableLiveData() - - fun getInstalledUser() { - launchOnUI { - mRepo.getGmsInstalledList(mInstalledLiveData) - } - } - - fun installGms(userID: Int) { - launchOnUI { - mRepo.installGms(userID,mUpdateInstalledLiveData) - } - } - - fun uninstallGms(userID: Int) { - launchOnUI { - mRepo.uninstallGms(userID,mUpdateInstalledLiveData) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/list/ListActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/list/ListActivity.kt deleted file mode 100644 index 36ff22a..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/list/ListActivity.kt +++ /dev/null @@ -1,157 +0,0 @@ -package top.niunaijun.blackboxa.view.list - -import android.app.Activity -import android.content.Context -import android.content.Intent -import android.os.Bundle -import android.view.Menu -import android.view.MenuItem -import android.view.inputmethod.InputMethodManager -import androidx.activity.result.contract.ActivityResultContracts -import androidx.lifecycle.ViewModelProvider -import androidx.recyclerview.widget.LinearLayoutManager -import cbfg.rvadapter.RVAdapter -import com.ferfalk.simplesearchview.SimpleSearchView -import top.niunaijun.blackboxa.R -import top.niunaijun.blackboxa.bean.InstalledAppBean -import top.niunaijun.blackboxa.databinding.ActivityListBinding -import top.niunaijun.blackboxa.util.InjectionUtil -import top.niunaijun.blackboxa.util.inflate -import top.niunaijun.blackboxa.view.base.BaseActivity - -class ListActivity : BaseActivity() { - - private val viewBinding: ActivityListBinding by inflate() - - private lateinit var mAdapter: RVAdapter - - private lateinit var viewModel: ListViewModel - - private var appList: List = ArrayList() - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(viewBinding.root) - - initToolbar(viewBinding.toolbarLayout.toolbar, R.string.installed_app, true) - - mAdapter = - RVAdapter(this, ListAdapter()) - .bind(viewBinding.recyclerView) - .setItemClickListener { _, item, _ -> finishWithResult(item.packageName) } - - viewBinding.recyclerView.layoutManager = LinearLayoutManager(this) - - initSearchView() - initViewModel() - } - - private fun initSearchView() { - viewBinding.searchView.setOnQueryTextListener( - object : SimpleSearchView.OnQueryTextListener { - override fun onQueryTextChange(newText: String): Boolean { - filterApp(newText) - return true - } - - override fun onQueryTextCleared(): Boolean { - return true - } - - override fun onQueryTextSubmit(query: String): Boolean { - return true - } - } - ) - } - - private fun initViewModel() { - viewModel = - ViewModelProvider(this, InjectionUtil.getListFactory()) - .get(ListViewModel::class.java) - val userID = intent.getIntExtra("userID", 0) - viewModel.getInstallAppList(userID) - viewBinding.toolbarLayout.toolbar.setTitle(R.string.installed_app) - - viewModel.loadingLiveData.observe(this) { - if (it) { - viewBinding.stateView.showLoading() - } else { - viewBinding.stateView.showContent() - } - } - - viewModel.appsLiveData.observe(this) { - if (it != null) { - this.appList = it - viewBinding.searchView.setQuery("", false) - filterApp("") - if (it.isNotEmpty()) { - viewBinding.stateView.showContent() - viewModel.previewInstalledList() - } else { - viewBinding.stateView.showEmpty() - } - } - } - } - - private fun filterApp(newText: String) { - val newList = - this.appList.filter { - it.name.contains(newText, true) or it.packageName.contains(newText, true) - } - mAdapter.setItems(newList) - } - - private val openDocumentedResult = - registerForActivityResult(ActivityResultContracts.GetContent()) { - it?.run { finishWithResult(it.toString()) } - } - - private fun finishWithResult(source: String) { - intent.putExtra("source", source) - setResult(Activity.RESULT_OK, intent) - val imm: InputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager - window.peekDecorView()?.run { imm.hideSoftInputFromWindow(windowToken, 0) } - finish() - } - - override fun onBackPressed() { - if (viewBinding.searchView.isSearchOpen) { - viewBinding.searchView.closeSearch() - } else { - super.onBackPressed() - } - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == R.id.list_choose) { - openDocumentedResult.launch("application/vnd.android.package-archive") - } - return true - } - - override fun onCreateOptionsMenu(menu: Menu?): Boolean { - menuInflater.inflate(R.menu.menu_list, menu) - val item = menu!!.findItem(R.id.list_search) - viewBinding.searchView.setMenuItem(item) - - return true - } - - override fun onStop() { - super.onStop() - viewModel.loadingLiveData.postValue(true) - viewModel.loadingLiveData.removeObservers(this) - viewModel.appsLiveData.postValue(null) - viewModel.appsLiveData.removeObservers(this) - } - - companion object { - fun start(context: Context) { - val intent = Intent(context, ListActivity::class.java) - context.startActivity(intent) - } - } -} diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/list/ListAdapter.kt b/app/src/main/java/top/niunaijun/blackboxa/view/list/ListAdapter.kt deleted file mode 100644 index df3aabb..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/list/ListAdapter.kt +++ /dev/null @@ -1,33 +0,0 @@ -package top.niunaijun.blackboxa.view.list - -import android.view.View -import android.view.ViewGroup -import cbfg.rvadapter.RVHolder -import cbfg.rvadapter.RVHolderFactory -import top.niunaijun.blackboxa.R -import top.niunaijun.blackboxa.bean.InstalledAppBean -import top.niunaijun.blackboxa.databinding.ItemPackageBinding - - - -class ListAdapter : RVHolderFactory() { - - override fun createViewHolder(parent: ViewGroup?, viewType: Int, item: Any): RVHolder { - return ListVH(inflate(R.layout.item_package,parent)) - } - - class ListVH(itemView:View) :RVHolder(itemView){ - - val binding = ItemPackageBinding.bind(itemView) - override fun setContent(item: InstalledAppBean, isSelected: Boolean, payload: Any?) { - binding.icon.setImageDrawable(item.icon) - binding.name.text = item.name - binding.packageName.text = item.packageName - binding.cornerLabel.visibility = if (item.isInstall) { - View.VISIBLE - } else { - View.GONE - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/list/ListFactory.kt b/app/src/main/java/top/niunaijun/blackboxa/view/list/ListFactory.kt deleted file mode 100644 index 6138b9f..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/list/ListFactory.kt +++ /dev/null @@ -1,14 +0,0 @@ -package top.niunaijun.blackboxa.view.list - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import top.niunaijun.blackboxa.data.AppsRepository - - -@Suppress("UNCHECKED_CAST") -class ListFactory(private val appsRepository: AppsRepository) : ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T { - return ListViewModel(appsRepository) as T - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/list/ListViewModel.kt b/app/src/main/java/top/niunaijun/blackboxa/view/list/ListViewModel.kt deleted file mode 100644 index 7e049d6..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/list/ListViewModel.kt +++ /dev/null @@ -1,22 +0,0 @@ -package top.niunaijun.blackboxa.view.list - -import androidx.lifecycle.MutableLiveData -import top.niunaijun.blackboxa.bean.InstalledAppBean -import top.niunaijun.blackboxa.data.AppsRepository -import top.niunaijun.blackboxa.view.base.BaseViewModel - - -class ListViewModel(private val repo: AppsRepository) : BaseViewModel() { - - val appsLiveData = MutableLiveData>() - - val loadingLiveData = MutableLiveData() - - fun previewInstalledList() { - launchOnUI { repo.previewInstallList() } - } - - fun getInstallAppList(userID: Int) { - launchOnUI { repo.getInstalledAppList(userID, loadingLiveData, appsLiveData) } - } -} diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/main/BlackBoxLoader.kt b/app/src/main/java/top/niunaijun/blackboxa/view/main/BlackBoxLoader.kt deleted file mode 100644 index 31a0fa2..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/main/BlackBoxLoader.kt +++ /dev/null @@ -1,318 +0,0 @@ -package top.niunaijun.blackboxa.view.main - -import android.app.Application -import android.content.Context -import android.util.Log -import java.io.File -import top.niunaijun.blackbox.BlackBoxCore -import top.niunaijun.blackbox.app.BActivityThread -import top.niunaijun.blackbox.app.configuration.AppLifecycleCallback -import top.niunaijun.blackbox.app.configuration.ClientConfiguration -import top.niunaijun.blackboxa.app.App -import top.niunaijun.blackboxa.app.rocker.RockerManager -import top.niunaijun.blackboxa.biz.cache.AppSharedPreferenceDelegate - - -class BlackBoxLoader { - - private var mHideRoot by AppSharedPreferenceDelegate(App.getContext(), false) - - private var mDaemonEnable by AppSharedPreferenceDelegate(App.getContext(), true) - private var mShowShortcutPermissionDialog by AppSharedPreferenceDelegate(App.getContext(), true) - - - private var mUseVpnNetwork by AppSharedPreferenceDelegate(App.getContext(), false) - - private var mDisableFlagSecure by AppSharedPreferenceDelegate(App.getContext(), false) - - fun hideRoot(): Boolean { - return try { - mHideRoot - } catch (e: Exception) { - Log.e(TAG, "Error getting hideRoot: ${e.message}") - false - } - } - - fun invalidHideRoot(hideRoot: Boolean) { - try { - this.mHideRoot = hideRoot - } catch (e: Exception) { - Log.e(TAG, "Error setting hideRoot: ${e.message}") - } - } - - fun disableFlagSecure(): Boolean { - return try { - mDisableFlagSecure - } catch (e: Exception) { - Log.e(TAG, "Error getting disableFlagSecure: ${e.message}") - false - } - } - - fun invalidDisableFlagSecure(disable: Boolean) { - try { - this.mDisableFlagSecure = disable - } catch (e: Exception) { - Log.e(TAG, "Error setting disableFlagSecure: ${e.message}") - } - } - - fun daemonEnable(): Boolean { - return try { - mDaemonEnable - } catch (e: Exception) { - Log.e(TAG, "Error getting daemonEnable: ${e.message}") - false - } - } - - fun invalidDaemonEnable(enable: Boolean) { - try { - this.mDaemonEnable = enable - } catch (e: Exception) { - Log.e(TAG, "Error setting daemonEnable: ${e.message}") - } - } - - fun showShortcutPermissionDialog(): Boolean { - return try { - mShowShortcutPermissionDialog - } catch (e: Exception) { - Log.e(TAG, "Error getting showShortcutPermissionDialog: ${e.message}") - true - } - } - - fun invalidShortcutPermissionDialog(show: Boolean) { - try { - this.mShowShortcutPermissionDialog = show - } catch (e: Exception) { - Log.e(TAG, "Error setting showShortcutPermissionDialog: ${e.message}") - } - } - - fun useVpnNetwork(): Boolean { - return try { - mUseVpnNetwork - } catch (e: Exception) { - Log.e(TAG, "Error getting useVpnNetwork: ${e.message}") - false - } - } - - fun invalidUseVpnNetwork(enable: Boolean) { - try { - this.mUseVpnNetwork = enable - } catch (e: Exception) { - Log.e(TAG, "Error setting useVpnNetwork: ${e.message}") - } - } - - fun getBlackBoxCore(): BlackBoxCore { - return try { - BlackBoxCore.get() - } catch (e: Exception) { - Log.e(TAG, "Error getting BlackBoxCore: ${e.message}") - throw e - } - } - - fun addLifecycleCallback() { - try { - BlackBoxCore.get() - .addAppLifecycleCallback( - object : AppLifecycleCallback() { - override fun beforeCreateApplication( - packageName: String?, - processName: String?, - context: Context?, - userId: Int - ) { - try { - Log.d( - TAG, - "beforeCreateApplication: pkg $packageName, processName $processName,userID:${BActivityThread.getUserId()}" - ) - } catch (e: Exception) { - Log.e(TAG, "Error in beforeCreateApplication: ${e.message}") - } - } - - override fun beforeApplicationOnCreate( - packageName: String?, - processName: String?, - application: Application?, - userId: Int - ) { - try { - Log.d( - TAG, - "beforeApplicationOnCreate: pkg $packageName, processName $processName" - ) - } catch (e: Exception) { - Log.e( - TAG, - "Error in beforeApplicationOnCreate: ${e.message}" - ) - } - } - - override fun afterApplicationOnCreate( - packageName: String?, - processName: String?, - application: Application?, - userId: Int - ) { - try { - Log.d( - TAG, - "afterApplicationOnCreate: pkg $packageName, processName $processName" - ) - RockerManager.init(application, userId) - } catch (e: Exception) { - Log.e( - TAG, - "Error in afterApplicationOnCreate: ${e.message}" - ) - } - } - - override fun onStoragePermissionNeeded( - packageName: String?, - userId: Int - ): Boolean { - try { - Log.w( - TAG, - "Storage permission needed for launching: $packageName" - ) - - - - val intent = - android.content.Intent( - "top.niunaijun.blackboxa.REQUEST_STORAGE_PERMISSION" - ) - intent.putExtra("package_name", packageName) - intent.putExtra("user_id", userId) - intent.setPackage(App.getContext().packageName) - App.getContext().sendBroadcast(intent) - - - - - - return false - } catch (e: Exception) { - Log.e( - TAG, - "Error in onStoragePermissionNeeded: ${e.message}" - ) - return false - } - } - } - ) - } catch (e: Exception) { - Log.e(TAG, "Error adding lifecycle callback: ${e.message}") - } - } - - fun attachBaseContext(context: Context) { - try { - BlackBoxCore.get() - .doAttachBaseContext( - context, - object : ClientConfiguration() { - override fun getHostPackageName(): String { - return try { - context.packageName - } catch (e: Exception) { - Log.e(TAG, "Error getting package name: ${e.message}") - "unknown" - } - } - - override fun isHideRoot(): Boolean { - return try { - mHideRoot - } catch (e: Exception) { - Log.e(TAG, "Error checking hideRoot: ${e.message}") - false - } - } - - override fun isEnableDaemonService(): Boolean { - return true - } - - override fun isUseVpnNetwork(): Boolean { - return try { - mUseVpnNetwork - } catch (e: Exception) { - Log.e(TAG, "Error checking useVpnNetwork: ${e.message}") - false - } - } - - override fun isDisableFlagSecure(): Boolean { - return try { - mDisableFlagSecure - } catch (e: Exception) { - Log.e(TAG, "Error checking disableFlagSecure: ${e.message}") - false - } - } - - override fun requestInstallPackage( - file: File?, - userId: Int - ): Boolean { - return try { - if (file == null) { - Log.w(TAG, "requestInstallPackage: file is null") - return false - } - val packageInfo = - context.packageManager.getPackageArchiveInfo( - file.absolutePath, - 0 - ) - false - } catch (e: Exception) { - Log.e(TAG, "Error in requestInstallPackage: ${e.message}") - false - } - } - } - ) - } catch (e: Exception) { - Log.e(TAG, "Error in attachBaseContext: ${e.message}") - } - } - - fun doOnCreate(context: Context) { - try { - BlackBoxCore.get().doCreate() - - - try { - BlackBoxCore.get().addServiceAvailableCallback { - Log.d(TAG, "Services became available, triggering app list refresh") - - - } - } catch (e: Exception) { - Log.e(TAG, "Error registering service available callback: ${e.message}") - } - } catch (e: Exception) { - Log.e(TAG, "Error in doOnCreate: ${e.message}") - } - } - - companion object { - val TAG: String = BlackBoxLoader::class.java.simpleName - } -} diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/main/MainActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/main/MainActivity.kt deleted file mode 100644 index 3844faa..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/main/MainActivity.kt +++ /dev/null @@ -1,434 +0,0 @@ -package top.niunaijun.blackboxa.view.main - -import android.content.Context -import android.content.Intent -import android.net.Uri -import android.net.VpnService -import android.os.Bundle -import android.util.Log -import android.view.Menu -import android.view.MenuItem -import androidx.activity.result.contract.ActivityResultContracts -import androidx.core.content.edit -import androidx.viewpager2.widget.ViewPager2 -import com.afollestad.materialdialogs.MaterialDialog -import com.afollestad.materialdialogs.input.input -import top.niunaijun.blackbox.BlackBoxCore -import top.niunaijun.blackboxa.R -import top.niunaijun.blackboxa.app.App -import top.niunaijun.blackboxa.app.AppManager -import top.niunaijun.blackboxa.databinding.ActivityMainBinding -import top.niunaijun.blackboxa.util.Resolution -import top.niunaijun.blackboxa.util.inflate -import top.niunaijun.blackboxa.view.apps.AppsFragment -import top.niunaijun.blackboxa.view.base.LoadingActivity -import top.niunaijun.blackboxa.view.fake.FakeManagerActivity -import top.niunaijun.blackboxa.view.list.ListActivity -import top.niunaijun.blackboxa.view.setting.SettingActivity - -class MainActivity : LoadingActivity() { - - private val viewBinding: ActivityMainBinding by inflate() - - private lateinit var mViewPagerAdapter: ViewPagerAdapter - - private val fragmentList = mutableListOf() - - private var currentUser = 0 - - companion object { - private const val TAG = "MainActivity" - private const val STORAGE_PERMISSION_REQUEST_CODE = 1001 - private const val VPN_PERMISSION_REQUEST_CODE = 1002 - - fun start(context: Context) { - val intent = Intent(context, MainActivity::class.java) - context.startActivity(intent) - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - try { - super.onCreate(savedInstanceState) - - try { - BlackBoxCore.get().onBeforeMainActivityOnCreate(this) - } catch (e: Exception) { - Log.e(TAG, "Error in onBeforeMainActivityOnCreate: ${e.message}") - } - - setContentView(viewBinding.root) - initToolbar(viewBinding.toolbarLayout.toolbar, R.string.app_name) - initViewPager() - initFab() - initToolbarSubTitle() - - - checkStoragePermission() - - - checkVpnPermission() - - try { - BlackBoxCore.get().onAfterMainActivityOnCreate(this) - } catch (e: Exception) { - Log.e(TAG, "Error in onAfterMainActivityOnCreate: ${e.message}") - } - } catch (e: Exception) { - Log.e(TAG, "Critical error in onCreate: ${e.message}") - - showErrorDialog("Failed to initialize app: ${e.message}") - } - } - - private fun checkStoragePermission() { - try { - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) { - - if (!android.os.Environment.isExternalStorageManager()) { - Log.w(TAG, "MANAGE_EXTERNAL_STORAGE permission not granted") - showStoragePermissionDialog() - } - } else { - - if (androidx.core.content.ContextCompat.checkSelfPermission( - this, - android.Manifest.permission.WRITE_EXTERNAL_STORAGE - ) != android.content.pm.PackageManager.PERMISSION_GRANTED || - androidx.core.content.ContextCompat.checkSelfPermission( - this, - android.Manifest.permission.READ_EXTERNAL_STORAGE - ) != android.content.pm.PackageManager.PERMISSION_GRANTED - ) { - Log.w( - TAG, - "Storage permissions not granted on Android ${android.os.Build.VERSION.SDK_INT}" - ) - requestLegacyStoragePermission() - } - } - } catch (e: Exception) { - Log.e(TAG, "Error checking storage permission: ${e.message}") - } - } - - private fun requestLegacyStoragePermission() { - try { - androidx.core.app.ActivityCompat.requestPermissions( - this, - arrayOf( - android.Manifest.permission.READ_EXTERNAL_STORAGE, - android.Manifest.permission.WRITE_EXTERNAL_STORAGE - ), - STORAGE_PERMISSION_REQUEST_CODE - ) - } catch (e: Exception) { - Log.e(TAG, "Error requesting storage permission: ${e.message}") - } - } - - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray - ) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - if (requestCode == STORAGE_PERMISSION_REQUEST_CODE) { - if (grantResults.isNotEmpty() && - grantResults.all { - it == android.content.pm.PackageManager.PERMISSION_GRANTED - } - ) { - Log.d(TAG, "Storage permissions granted") - } else { - Log.w(TAG, "Storage permissions denied") - } - } - } - - private fun showStoragePermissionDialog() { - try { - MaterialDialog(this).show { - title(text = "Storage Permission Required") - message( - text = - "This app needs 'All Files Access' permission to properly run sandboxed apps. Without this permission, some apps may not work correctly.\n\nPlease grant permission in the next screen." - ) - positiveButton(text = "Grant Permission") { openAllFilesAccessSettings() } - negativeButton(text = "Later") { Log.w(TAG, "User postponed storage permission") } - cancelable(false) - } - } catch (e: Exception) { - Log.e(TAG, "Error showing storage permission dialog: ${e.message}") - } - } - - private fun openAllFilesAccessSettings() { - try { - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) { - val intent = - Intent( - android.provider.Settings - .ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION - ) - intent.data = Uri.parse("package:$packageName") - storagePermissionResult.launch(intent) - } - } catch (e: Exception) { - Log.e(TAG, "Error opening storage settings: ${e.message}") - - try { - val intent = - Intent(android.provider.Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION) - storagePermissionResult.launch(intent) - } catch (e2: Exception) { - Log.e(TAG, "Error opening fallback storage settings: ${e2.message}") - } - } - } - - private val storagePermissionResult = - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - try { - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) { - if (android.os.Environment.isExternalStorageManager()) { - Log.d(TAG, "Storage permission granted!") - } else { - Log.w(TAG, "Storage permission still not granted") - } - } - } catch (e: Exception) { - Log.e(TAG, "Error handling storage permission result: ${e.message}") - } - } - - - private fun checkVpnPermission() { - try { - val vpnIntent = VpnService.prepare(this) - if (vpnIntent != null) { - - Log.d(TAG, "VPN permission not granted, requesting...") - vpnPermissionResult.launch(vpnIntent) - } else { - - Log.d(TAG, "VPN permission already granted") - } - } catch (e: Exception) { - Log.e(TAG, "Error checking VPN permission: ${e.message}") - } - } - - private val vpnPermissionResult = - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> - try { - if (result.resultCode == RESULT_OK) { - Log.d(TAG, "VPN permission granted!") - - } else { - Log.w(TAG, "VPN permission denied by user") - } - } catch (e: Exception) { - Log.e(TAG, "Error handling VPN permission result: ${e.message}") - } - } - - private fun showErrorDialog(message: String) { - try { - MaterialDialog(this).show { - title(text = "Error") - message(text = message) - positiveButton(text = "OK") { finish() } - } - } catch (e: Exception) { - Log.e(TAG, "Error showing error dialog: ${e.message}") - finish() - } - } - - private fun initToolbarSubTitle() { - try { - updateUserRemark(0) - - viewBinding.toolbarLayout.toolbar.getChildAt(1)?.setOnClickListener { - try { - MaterialDialog(this).show { - title(res = R.string.userRemark) - input( - hintRes = R.string.userRemark, - prefill = viewBinding.toolbarLayout.toolbar.subtitle - ) { _, input -> - try { - AppManager.mRemarkSharedPreferences.edit { - putString("Remark$currentUser", input.toString()) - viewBinding.toolbarLayout.toolbar.subtitle = input - } - } catch (e: Exception) { - Log.e(TAG, "Error saving user remark: ${e.message}") - } - } - positiveButton(res = R.string.done) - negativeButton(res = R.string.cancel) - } - } catch (e: Exception) { - Log.e(TAG, "Error showing remark dialog: ${e.message}") - } - } - } catch (e: Exception) { - Log.e(TAG, "Error in initToolbarSubTitle: ${e.message}") - } - } - - private fun initViewPager() { - try { - val userList = BlackBoxCore.get().users - userList.forEach { fragmentList.add(AppsFragment.newInstance(it.id)) } - - currentUser = userList.firstOrNull()?.id ?: 0 - fragmentList.add(AppsFragment.newInstance(userList.size)) - - mViewPagerAdapter = ViewPagerAdapter(this) - mViewPagerAdapter.replaceData(fragmentList) - viewBinding.viewPager.adapter = mViewPagerAdapter - viewBinding.dotsIndicator.setViewPager2(viewBinding.viewPager) - viewBinding.viewPager.registerOnPageChangeCallback( - object : ViewPager2.OnPageChangeCallback() { - override fun onPageSelected(position: Int) { - try { - super.onPageSelected(position) - currentUser = fragmentList[position].userID - updateUserRemark(currentUser) - showFloatButton(true) - } catch (e: Exception) { - Log.e(TAG, "Error in onPageSelected: ${e.message}") - } - } - } - ) - } catch (e: Exception) { - Log.e(TAG, "Error in initViewPager: ${e.message}") - } - } - - private fun initFab() { - try { - viewBinding.fab.setOnClickListener { - try { - val userId = viewBinding.viewPager.currentItem - val intent = Intent(this, ListActivity::class.java) - intent.putExtra("userID", userId) - apkPathResult.launch(intent) - } catch (e: Exception) { - Log.e(TAG, "Error launching ListActivity: ${e.message}") - } - } - } catch (e: Exception) { - Log.e(TAG, "Error in initFab: ${e.message}") - } - } - - fun showFloatButton(show: Boolean) { - try { - val tranY: Float = Resolution.convertDpToPixel(120F, App.getContext()) - val time = 200L - if (show) { - viewBinding.fab.animate().translationY(0f).alpha(1f).setDuration(time).start() - } else { - viewBinding.fab.animate().translationY(tranY).alpha(0f).setDuration(time).start() - } - } catch (e: Exception) { - Log.e(TAG, "Error in showFloatButton: ${e.message}") - } - } - - fun scanUser() { - try { - val userList = BlackBoxCore.get().users - - if (fragmentList.size == userList.size) { - fragmentList.add(AppsFragment.newInstance(fragmentList.size)) - } else if (fragmentList.size > userList.size + 1) { - fragmentList.removeLast() - } - - mViewPagerAdapter.notifyDataSetChanged() - } catch (e: Exception) { - Log.e(TAG, "Error in scanUser: ${e.message}") - } - } - - private fun updateUserRemark(userId: Int) { - try { - var remark = - AppManager.mRemarkSharedPreferences.getString("Remark$userId", "User $userId") - if (remark.isNullOrEmpty()) { - remark = "User $userId" - } - - viewBinding.toolbarLayout.toolbar.subtitle = remark - } catch (e: Exception) { - Log.e(TAG, "Error updating user remark: ${e.message}") - viewBinding.toolbarLayout.toolbar.subtitle = "User $userId" - } - } - - private val apkPathResult = - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - try { - if (it.resultCode == RESULT_OK) { - it.data?.let { data -> - val userId = data.getIntExtra("userID", 0) - val source = data.getStringExtra("source") - if (source != null) { - fragmentList[userId].installApk(source) - } - } - } - } catch (e: Exception) { - Log.e(TAG, "Error handling APK path result: ${e.message}") - } - } - - override fun onCreateOptionsMenu(menu: Menu?): Boolean { - try { - menuInflater.inflate(R.menu.menu_main, menu) - return true - } catch (e: Exception) { - Log.e(TAG, "Error creating options menu: ${e.message}") - return false - } - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - try { - when (item.itemId) { - R.id.main_git -> { - val intent = - Intent( - Intent.ACTION_VIEW, - Uri.parse("https://github.com/ALEX5402/NewBlackbox") - ) - startActivity(intent) - } - R.id.main_setting -> { - SettingActivity.start(this) - } - R.id.main_tg -> { - val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://t.me/newblackboxa")) - startActivity(intent) - } - R.id.fake_location -> { - - val intent = Intent(this, FakeManagerActivity::class.java) - intent.putExtra("userID", 0) - startActivity(intent) - } - } - - return true - } catch (e: Exception) { - Log.e(TAG, "Error handling menu item selection: ${e.message}") - return false - } - } -} diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/main/ShortcutActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/main/ShortcutActivity.kt deleted file mode 100644 index f72655a..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/main/ShortcutActivity.kt +++ /dev/null @@ -1,23 +0,0 @@ -package top.niunaijun.blackboxa.view.main - -import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.lifecycleScope -import kotlinx.coroutines.launch -import top.niunaijun.blackbox.BlackBoxCore - - -class ShortcutActivity:AppCompatActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - val pkg = intent.getStringExtra("pkg") - val userID = intent.getIntExtra("userId",0) - - lifecycleScope.launch { - BlackBoxCore.get().launchApk(pkg,userID) - finish() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/main/ViewPagerAdapter.kt b/app/src/main/java/top/niunaijun/blackboxa/view/main/ViewPagerAdapter.kt deleted file mode 100644 index 1c27627..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/main/ViewPagerAdapter.kt +++ /dev/null @@ -1,27 +0,0 @@ -package top.niunaijun.blackboxa.view.main - -import androidx.appcompat.app.AppCompatActivity -import androidx.fragment.app.Fragment -import androidx.viewpager2.adapter.FragmentStateAdapter -import top.niunaijun.blackboxa.view.apps.AppsFragment - - - -class ViewPagerAdapter(appCompatActivity: AppCompatActivity) : FragmentStateAdapter(appCompatActivity) { - - private var fragmentList = mutableListOf() - - fun replaceData(list: MutableList){ - this.fragmentList = list - notifyDataSetChanged() - } - - override fun getItemCount(): Int { - return fragmentList.size - } - - override fun createFragment(position: Int): Fragment { - return fragmentList[position] - } - -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/main/WelcomeActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/main/WelcomeActivity.kt deleted file mode 100644 index 3f3586d..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/main/WelcomeActivity.kt +++ /dev/null @@ -1,34 +0,0 @@ -package top.niunaijun.blackboxa.view.main - -import android.content.Intent -import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.ViewModelProvider -import top.niunaijun.blackbox.BlackBoxCore -import top.niunaijun.blackboxa.util.InjectionUtil -import top.niunaijun.blackboxa.view.list.ListViewModel -import top.niunaijun.blackboxa.fridabox.FridaBoxActivity - -class WelcomeActivity : AppCompatActivity() { - - override fun onNewIntent(intent: Intent?) { - super.onNewIntent(intent) - jump() - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - previewInstalledAppList() - jump() - } - - private fun jump() { - startActivity(Intent(this, FridaBoxActivity::class.java)) - finish() - } - - private fun previewInstalledAppList(){ - val viewModel = ViewModelProvider(this,InjectionUtil.getListFactory()).get(ListViewModel::class.java) - viewModel.previewInstalledList() - } -} diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/setting/SettingActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/setting/SettingActivity.kt deleted file mode 100644 index 88ee833..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/setting/SettingActivity.kt +++ /dev/null @@ -1,32 +0,0 @@ -package top.niunaijun.blackboxa.view.setting - -import android.content.Context -import android.content.Intent -import android.os.Bundle -import top.niunaijun.blackboxa.R -import top.niunaijun.blackboxa.databinding.ActivitySettingBinding -import top.niunaijun.blackboxa.util.inflate -import top.niunaijun.blackboxa.view.base.BaseActivity - -class SettingActivity : BaseActivity() { - - private val viewBinding: ActivitySettingBinding by inflate() - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(viewBinding.root) - initToolbar(viewBinding.toolbarLayout.toolbar, R.string.setting, true) - supportFragmentManager.beginTransaction() - .replace(R.id.fragment, SettingFragment()) - .commit() - } - - companion object{ - fun start(context: Context){ - val intent = Intent(context,SettingActivity::class.java) - intent.action = Intent.ACTION_OPEN_DOCUMENT - context.startActivity(intent) - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/setting/SettingFragment.kt b/app/src/main/java/top/niunaijun/blackboxa/view/setting/SettingFragment.kt deleted file mode 100644 index c0a2dc0..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/view/setting/SettingFragment.kt +++ /dev/null @@ -1,111 +0,0 @@ -package top.niunaijun.blackboxa.view.setting - -import android.os.Bundle -import androidx.preference.Preference -import androidx.preference.PreferenceFragmentCompat -import top.niunaijun.blackbox.BlackBoxCore -import top.niunaijun.blackboxa.R -import top.niunaijun.blackboxa.app.AppManager -import top.niunaijun.blackboxa.util.toast -import top.niunaijun.blackboxa.view.gms.GmsManagerActivity - -class SettingFragment : PreferenceFragmentCompat() { - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setPreferencesFromResource(R.xml.setting, rootKey) - - initGms() - - invalidHideState { - val rootHidePreference: Preference = (findPreference("root_hide")!!) - val hideRoot = AppManager.mBlackBoxLoader.hideRoot() - rootHidePreference.setDefaultValue(hideRoot) - rootHidePreference - } - - invalidHideState { - val daemonPreference: Preference = (findPreference("daemon_enable")!!) - val mDaemonEnable = AppManager.mBlackBoxLoader.daemonEnable() - daemonPreference.setDefaultValue(mDaemonEnable) - daemonPreference - } - - invalidHideState { - val vpnPreference: Preference = (findPreference("use_vpn_network")!!) - val mUseVpnNetwork = AppManager.mBlackBoxLoader.useVpnNetwork() - vpnPreference.setDefaultValue(mUseVpnNetwork) - vpnPreference - } - - invalidHideState { - val disableFlagSecurePreference: Preference = (findPreference("disable_flag_secure")!!) - val mDisableFlagSecure = AppManager.mBlackBoxLoader.disableFlagSecure() - disableFlagSecurePreference.setDefaultValue(mDisableFlagSecure) - disableFlagSecurePreference - } - - initSendLogs() - } - - private fun initGms() { - val gmsManagerPreference: Preference = (findPreference("gms_manager")!!) - - if (BlackBoxCore.get().isSupportGms) { - - gmsManagerPreference.setOnPreferenceClickListener { - GmsManagerActivity.start(requireContext()) - true - } - } else { - gmsManagerPreference.summary = getString(R.string.no_gms) - gmsManagerPreference.isEnabled = false - } - } - - private fun invalidHideState(block: () -> Preference) { - val pref = block() - pref.setOnPreferenceChangeListener { preference, newValue -> - val tmpHide = (newValue == true) - when (preference.key) { - "root_hide" -> { - - AppManager.mBlackBoxLoader.invalidHideRoot(tmpHide) - } - "daemon_enable" -> { - AppManager.mBlackBoxLoader.invalidDaemonEnable(tmpHide) - } - "use_vpn_network" -> { - AppManager.mBlackBoxLoader.invalidUseVpnNetwork(tmpHide) - } - "disable_flag_secure" -> { - AppManager.mBlackBoxLoader.invalidDisableFlagSecure(tmpHide) - } - } - - toast(R.string.restart_module) - return@setOnPreferenceChangeListener true - } - } - private fun initSendLogs() { - val sendLogsPreference: Preference? = findPreference("send_logs") - sendLogsPreference?.setOnPreferenceClickListener { - it.isEnabled = false - BlackBoxCore.get() - .sendLogs( - "Manual Log Upload from Settings", - true, - object : BlackBoxCore.LogSendListener { - override fun onSuccess() { - activity?.runOnUiThread { sendLogsPreference.isEnabled = true } - } - - override fun onFailure(error: String?) { - activity?.runOnUiThread { sendLogsPreference.isEnabled = true } - } - } - ) - toast("Sending logs... (Check notifications for status)") - true - } - } -} diff --git a/app/src/main/java/top/niunaijun/blackboxa/widget/EnFloatView.kt b/app/src/main/java/top/niunaijun/blackboxa/widget/EnFloatView.kt deleted file mode 100644 index 60849d3..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/widget/EnFloatView.kt +++ /dev/null @@ -1,52 +0,0 @@ -package top.niunaijun.blackboxa.widget - -import android.content.Context -import android.view.MotionEvent -import com.imuxuan.floatingview.FloatingMagnetView -import top.niunaijun.blackboxa.R - - -class EnFloatView(mContext: Context) : FloatingMagnetView(mContext) { - - private val TAG = "RockerManager" - - private var rockerView: RockerView? = null - - private var mListener: LocationListener? = null - - init { - inflate(mContext, R.layout.view_float_rocker, this) - initRockerView() - } - - private fun initRockerView() { - - rockerView = findViewById(R.id.rocker) - rockerView?.setListener { type, currentAngle, currentDistance -> - if (type == RockerView.EVENT_CLOCK && currentAngle != -1F) { - val realAngle = currentAngle - val realDistance = currentDistance * 0.001F - - - mListener?.invoke(realAngle, realDistance) - - } - } - } - - override fun onTouchEvent(event: MotionEvent?): Boolean { - if (event?.action == MotionEvent.ACTION_DOWN) { - rockerView?.setCanMove(false) - } else if (event?.action == MotionEvent.ACTION_UP) { - rockerView?.setCanMove(true) - } - return super.onTouchEvent(event) - } - - fun setListener(listener: LocationListener) { - this.mListener = listener - } - -} - -typealias LocationListener = (angle: Float, distance: Float) -> Unit \ No newline at end of file diff --git a/app/src/main/java/top/niunaijun/blackboxa/widget/RockerView.java b/app/src/main/java/top/niunaijun/blackboxa/widget/RockerView.java deleted file mode 100644 index 1c37131..0000000 --- a/app/src/main/java/top/niunaijun/blackboxa/widget/RockerView.java +++ /dev/null @@ -1,441 +0,0 @@ -package top.niunaijun.blackboxa.widget; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.PixelFormat; -import android.graphics.Point; -import android.graphics.PorterDuff; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.util.Log; -import android.view.MotionEvent; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.View; - -import androidx.annotation.NonNull; - -import top.niunaijun.blackboxa.util.MathUtil; - - - -public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.Callback { - - private static final int DEFAULT_AREA_RADIUS = 100; - private static final int DEFAULT_ROCKER_RADIUS = 35; - - private static final int DEFAULT_AREA_COLOR = Color.argb(128,0,0,0); - private static final int DEFAULT_ROCKER_COLOR = Color.argb(128,0,0,0); - - private static final int DEFAULT_REFRESH_CYCLE = 30; - private static final int DEFAULT_CALLBACK_CYCLE = 300; - - private SurfaceHolder mHolder; - private static Thread mDrawThread; - private static Thread mCallbackThread; - private static boolean mDrawOk = true; - private static boolean mCallbackOk = true; - - private Paint mPaint; - - - private Point mAreaPosition; - - - private Point mRockerPosition; - - - private int mAreaRadius = -1; - private int mRockerRadius = -1; - - private int mAreaColor; - private int mRockerColor; - private Bitmap mAreaBitmap; - private Bitmap mRockerBitmap; - - private boolean canMove = true; - - - private RockerListener mListener; - public static final int EVENT_ACTION = 1; - public static final int EVENT_CLOCK = 2; - - private int mRefreshCycle = DEFAULT_REFRESH_CYCLE; - private int mCallbackCycle = DEFAULT_CALLBACK_CYCLE; - - - - - public RockerView(Context context) { - this(context, null); - } - - public RockerView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public RockerView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - - - initAttrs(context, attrs); - - - setPaint(); - - if (isInEditMode()) { - return; - } - - - configSurfaceView(); - - - configSurfaceHolder(); - } - - private void initAttrs(Context context, AttributeSet attrs) { - mAreaColor = DEFAULT_AREA_COLOR; - mRockerColor = DEFAULT_ROCKER_COLOR; - mAreaRadius = DEFAULT_AREA_RADIUS; - mRockerRadius = DEFAULT_ROCKER_RADIUS; - - } - - private void setPaint() { - mPaint = new Paint(); - mPaint.setAntiAlias(true); - } - - private void configSurfaceView() { - setKeepScreenOn(true); - setFocusable(true); - setFocusableInTouchMode(true); - setZOrderOnTop(true); - } - - private void configSurfaceHolder() { - mHolder = getHolder(); - mHolder.addCallback(this); - mHolder.setFormat(PixelFormat.TRANSPARENT); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int measureWidth = 0, measureHeight = 0; - int defaultWidth = (mAreaRadius + mRockerRadius) * 2; - int defalutHeight = defaultWidth; - - int widthsize = MeasureSpec.getSize(widthMeasureSpec); - int widthmode = MeasureSpec.getMode(widthMeasureSpec); - - int heightsize = MeasureSpec.getSize(heightMeasureSpec); - int heightmode = MeasureSpec.getMode(heightMeasureSpec); - - if (widthmode == MeasureSpec.AT_MOST || widthmode == MeasureSpec.UNSPECIFIED || widthsize < 0) { - measureWidth = defaultWidth; - } else { - measureWidth = widthsize; - } - - - if (heightmode == MeasureSpec.AT_MOST || heightmode == MeasureSpec.UNSPECIFIED || heightsize < 0) { - measureHeight = defalutHeight; - } else { - measureHeight = heightsize; - } - - setMeasuredDimension(measureWidth, measureHeight); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - - mAreaPosition = new Point(w / 2, h / 2); - mRockerPosition = new Point(mAreaPosition); - - - int tempRadius = Math.min(w - getPaddingLeft() - getPaddingRight(), h - getPaddingTop() - getPaddingBottom()); - tempRadius /= 2; - if (mAreaRadius == -1) - mAreaRadius = (int) (tempRadius * 0.75); - if (mRockerRadius == -1) - mRockerRadius = (int) (tempRadius * 0.25); - } - - @Override - public void surfaceCreated(SurfaceHolder holder) { - try { - mDrawThread = new Thread(this); - mDrawThread.start(); - - mCallbackThread = new Thread(() -> { - while (mCallbackOk) { - - - listenerCallback(); - - try { - Thread.sleep(mCallbackCycle); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - mCallbackThread.start(); - - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - } - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - mDrawOk = false; - mCallbackOk = false; - } - - @Override - protected void onVisibilityChanged(@NonNull View changedView, int visibility) { - super.onVisibilityChanged(changedView, visibility); - if (visibility == VISIBLE) { - mDrawOk = true; - mCallbackOk = true; - } else { - mDrawOk = false; - mCallbackOk = false; - } - } - - - - @Override - public boolean onTouchEvent(MotionEvent event) { - try { - int len = MathUtil.getDistance(mAreaPosition.x, mAreaPosition.y, event.getX(), event.getY()); - - if (event.getAction() == MotionEvent.ACTION_DOWN) { - - if (len > mAreaRadius) { - return true; - } - } - - if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (len <= mAreaRadius) { - - mRockerPosition.set((int) event.getX(), (int) event.getY()); - - } else { - - mRockerPosition = MathUtil.getPointByCutLength(mAreaPosition, - new Point((int) event.getX(), (int) event.getY()), mAreaRadius); - } - if (mListener != null) { - float radian = MathUtil.getRadian(mAreaPosition, new Point((int) event.getX(), (int) event.getY())); - float angle = RockerView.this.getAngleConvert(radian); - float distance = MathUtil.getDistance(mAreaPosition.x, mAreaPosition.y, event.getX(), event.getY()); - mListener.callback(EVENT_ACTION, angle, distance); - } - } - - if (event.getAction() == MotionEvent.ACTION_UP) { - mRockerPosition = new Point(mAreaPosition); - if (mListener != null) { - mListener.callback(EVENT_ACTION, -1, 0); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - return true; - } - - - - - @Override - public void run() { - if (isInEditMode()) { - return; - } - - Canvas canvas = null; - - while (mDrawOk) { - boolean canMove = this.canMove; - try { - if (canMove) { - canvas = mHolder.lockCanvas(); - canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); - - drawArea(canvas); - drawRocker(canvas); - } - Thread.sleep(mRefreshCycle); - - } catch (Exception e) { - e.printStackTrace(); - } finally { - if (canvas != null && canMove) { - mHolder.unlockCanvasAndPost(canvas); - } - } - } - } - - private void drawArea(Canvas canvas) { - - if (null != mAreaBitmap) { - mPaint.setColor(Color.BLACK); - Rect src = new Rect(0, 0, mAreaBitmap.getWidth(), mAreaBitmap.getHeight()); - Rect dst = new Rect( - mAreaPosition.x - mAreaRadius, - mAreaPosition.y - mAreaRadius, - mAreaPosition.x + mAreaRadius, - mAreaPosition.y + mAreaRadius); - canvas.drawBitmap(mAreaBitmap, src, dst, mPaint); - } else { - mPaint.setColor(mAreaColor); - canvas.drawCircle(mAreaPosition.x, mAreaPosition.y, mAreaRadius, mPaint); - } - } - - private void drawRocker(Canvas canvas) { - if (null != mRockerBitmap) { - mPaint.setColor(Color.BLACK); - Rect src = new Rect(0, 0, mRockerBitmap.getWidth(), mRockerBitmap.getHeight()); - Rect dst = new Rect( - mRockerPosition.x - mRockerRadius, - mRockerPosition.y - mRockerRadius, - mRockerPosition.x + mRockerRadius, - mRockerPosition.y + mRockerRadius); - canvas.drawBitmap(mRockerBitmap, src, dst, mPaint); - } else { - mPaint.setColor(mRockerColor); - canvas.drawCircle(mRockerPosition.x, mRockerPosition.y, mRockerRadius, mPaint); - } - } - - private void listenerCallback() { - if (mListener != null) { - if (mRockerPosition.x == mAreaPosition.x && mRockerPosition.y == mAreaPosition.y) { - mListener.callback(EVENT_CLOCK, -1, 0); - } else { - float radian = MathUtil.getRadian(mAreaPosition, new Point(mRockerPosition.x, mRockerPosition.y)); - float angle = RockerView.this.getAngleConvert(radian); - float distance = MathUtil.getDistance(mAreaPosition.x, mAreaPosition.y, mRockerPosition.x, mRockerPosition.y); - mListener.callback(EVENT_CLOCK, angle, distance); - } - } - } - - - private float getAngleConvert(float radian) { - return 90 + Math.round(radian / Math.PI * 180); - } - - - @Override - protected void onDraw(Canvas canvas) { - if (isInEditMode()) { - canvas.drawColor(Color.WHITE); - drawArea(canvas); - drawRocker(canvas); - } - } - - - - public void setCanMove(boolean isMove) { - this.canMove = isMove; - } - - public int getAreaRadius() { - return mAreaRadius; - } - - public void setAreaRadius(int areaRadius) { - mAreaRadius = areaRadius; - } - - public int getRockerRadius() { - return mRockerRadius; - } - - public void setRockerRadius(int rockerRadius) { - mRockerRadius = rockerRadius; - } - - public Bitmap getAreaBitmap() { - return mAreaBitmap; - } - - public void setAreaBitmap(Bitmap areaBitmap) { - mAreaBitmap = areaBitmap; - } - - public Bitmap getRockerBitmap() { - return mRockerBitmap; - } - - public void setRockerBitmap(Bitmap rockerBitmap) { - mRockerBitmap = rockerBitmap; - } - - public int getRefreshCycle() { - return mRefreshCycle; - } - - public void setRefreshCycle(int refreshCycle) { - mRefreshCycle = refreshCycle; - } - - public int getCallbackCycle() { - return mCallbackCycle; - } - - public void setCallbackCycle(int callbackCycle) { - mCallbackCycle = callbackCycle; - } - - public int getAreaColor() { - return mAreaColor; - } - - public void setAreaColor(int areaColor) { - mAreaColor = areaColor; - mAreaBitmap = null; - } - - public int getRockerColor() { - return mRockerColor; - } - - public void setRockerColor(int rockerColor) { - mRockerColor = rockerColor; - mRockerBitmap = null; - } - - public void setListener(@NonNull RockerListener listener) { - mListener = listener; - } - - - - - public interface RockerListener { - - - void callback(int eventType, float currentAngle, float currentDistance); - } - -} \ No newline at end of file diff --git a/app/src/main/res/drawable-anydpi/ic_add.xml b/app/src/main/res/drawable-anydpi/ic_add.xml deleted file mode 100644 index 672478e..0000000 --- a/app/src/main/res/drawable-anydpi/ic_add.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/app/src/main/res/drawable-anydpi/ic_location_change.xml b/app/src/main/res/drawable-anydpi/ic_location_change.xml deleted file mode 100644 index f9217b9..0000000 --- a/app/src/main/res/drawable-anydpi/ic_location_change.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/app/src/main/res/drawable-anydpi/ic_search.xml b/app/src/main/res/drawable-anydpi/ic_search.xml deleted file mode 100644 index 44dcb4a..0000000 --- a/app/src/main/res/drawable-anydpi/ic_search.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/app/src/main/res/drawable-hdpi/ic_add.png b/app/src/main/res/drawable-hdpi/ic_add.png deleted file mode 100644 index f8c47ab..0000000 Binary files a/app/src/main/res/drawable-hdpi/ic_add.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_location_change.png b/app/src/main/res/drawable-hdpi/ic_location_change.png deleted file mode 100644 index 096c1d9..0000000 Binary files a/app/src/main/res/drawable-hdpi/ic_location_change.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_search.png b/app/src/main/res/drawable-hdpi/ic_search.png deleted file mode 100644 index 9c5dd04..0000000 Binary files a/app/src/main/res/drawable-hdpi/ic_search.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_add.png b/app/src/main/res/drawable-mdpi/ic_add.png deleted file mode 100644 index 3b9883f..0000000 Binary files a/app/src/main/res/drawable-mdpi/ic_add.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_location_change.png b/app/src/main/res/drawable-mdpi/ic_location_change.png deleted file mode 100644 index 4cf546a..0000000 Binary files a/app/src/main/res/drawable-mdpi/ic_location_change.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_search.png b/app/src/main/res/drawable-mdpi/ic_search.png deleted file mode 100644 index aa59a7d..0000000 Binary files a/app/src/main/res/drawable-mdpi/ic_search.png and /dev/null differ diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 912980c..0000000 --- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/ic_add.png b/app/src/main/res/drawable-xhdpi/ic_add.png deleted file mode 100644 index a8e615a..0000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_add.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_location_change.png b/app/src/main/res/drawable-xhdpi/ic_location_change.png deleted file mode 100644 index b0f2914..0000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_location_change.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_search.png b/app/src/main/res/drawable-xhdpi/ic_search.png deleted file mode 100644 index 9c758db..0000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_search.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_add.png b/app/src/main/res/drawable-xxhdpi/ic_add.png deleted file mode 100644 index bd150a3..0000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_add.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_location_change.png b/app/src/main/res/drawable-xxhdpi/ic_location_change.png deleted file mode 100644 index 052953f..0000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_location_change.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_search.png b/app/src/main/res/drawable-xxhdpi/ic_search.png deleted file mode 100644 index 485f671..0000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_search.png and /dev/null differ diff --git a/app/src/main/res/drawable/ic_empty.xml b/app/src/main/res/drawable/ic_empty.xml deleted file mode 100644 index fbfea1c..0000000 --- a/app/src/main/res/drawable/ic_empty.xml +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 6ae213e..0000000 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/splash.xml b/app/src/main/res/drawable/splash.xml deleted file mode 100644 index 3dd706a..0000000 --- a/app/src/main/res/drawable/splash.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_gms.xml b/app/src/main/res/layout/activity_gms.xml deleted file mode 100644 index 01de618..0000000 --- a/app/src/main/res/layout/activity_gms.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_list.xml b/app/src/main/res/layout/activity_list.xml deleted file mode 100644 index 85d8c5d..0000000 --- a/app/src/main/res/layout/activity_list.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index becefba..0000000 --- a/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_osmdroid.xml b/app/src/main/res/layout/activity_osmdroid.xml deleted file mode 100644 index 38a580f..0000000 --- a/app/src/main/res/layout/activity_osmdroid.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_setting.xml b/app/src/main/res/layout/activity_setting.xml deleted file mode 100644 index cc62e10..0000000 --- a/app/src/main/res/layout/activity_setting.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_xp.xml b/app/src/main/res/layout/activity_xp.xml deleted file mode 100644 index 4dc107e..0000000 --- a/app/src/main/res/layout/activity_xp.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/base_empty.xml b/app/src/main/res/layout/base_empty.xml deleted file mode 100644 index 43b6d67..0000000 --- a/app/src/main/res/layout/base_empty.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_apps.xml b/app/src/main/res/layout/fragment_apps.xml deleted file mode 100644 index efbd9c9..0000000 --- a/app/src/main/res/layout/fragment_apps.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_app.xml b/app/src/main/res/layout/item_app.xml deleted file mode 100644 index ce8133c..0000000 --- a/app/src/main/res/layout/item_app.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_fake.xml b/app/src/main/res/layout/item_fake.xml deleted file mode 100644 index d275319..0000000 --- a/app/src/main/res/layout/item_fake.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_gms.xml b/app/src/main/res/layout/item_gms.xml deleted file mode 100644 index 8cfbbce..0000000 --- a/app/src/main/res/layout/item_gms.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_package.xml b/app/src/main/res/layout/item_package.xml deleted file mode 100644 index 4588328..0000000 --- a/app/src/main/res/layout/item_package.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_viewpager.xml b/app/src/main/res/layout/item_viewpager.xml deleted file mode 100644 index 5787446..0000000 --- a/app/src/main/res/layout/item_viewpager.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_xp.xml b/app/src/main/res/layout/item_xp.xml deleted file mode 100644 index 83b901e..0000000 --- a/app/src/main/res/layout/item_xp.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/view_float_rocker.xml b/app/src/main/res/layout/view_float_rocker.xml deleted file mode 100644 index 87b0e4c..0000000 --- a/app/src/main/res/layout/view_float_rocker.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/view_switch.xml b/app/src/main/res/layout/view_switch.xml deleted file mode 100644 index 13ee034..0000000 --- a/app/src/main/res/layout/view_switch.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/view_toolbar.xml b/app/src/main/res/layout/view_toolbar.xml deleted file mode 100644 index e4461fa..0000000 --- a/app/src/main/res/layout/view_toolbar.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - diff --git a/app/src/main/res/menu/app_menu.xml b/app/src/main/res/menu/app_menu.xml deleted file mode 100644 index 72c1c2f..0000000 --- a/app/src/main/res/menu/app_menu.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/menu_list.xml b/app/src/main/res/menu/menu_list.xml deleted file mode 100644 index 8943922..0000000 --- a/app/src/main/res/menu/menu_list.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml deleted file mode 100644 index ffcfeff..0000000 --- a/app/src/main/res/menu/menu_main.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/menu_search.xml b/app/src/main/res/menu/menu_search.xml deleted file mode 100644 index fe3a141..0000000 --- a/app/src/main/res/menu/menu_search.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index e07b09b..0000000 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_beta.png b/app/src/main/res/mipmap-hdpi/ic_launcher_beta.png deleted file mode 100644 index 322e2d1..0000000 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_beta.png and /dev/null differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index b18fecf..0000000 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round_beta.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round_beta.png deleted file mode 100644 index eda9ed5..0000000 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round_beta.png and /dev/null differ diff --git a/app/src/main/res/mipmap-ldpi/ic_launcher.png b/app/src/main/res/mipmap-ldpi/ic_launcher.png deleted file mode 100644 index 36f32f7..0000000 Binary files a/app/src/main/res/mipmap-ldpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/mipmap-ldpi/ic_launcher_beta.png b/app/src/main/res/mipmap-ldpi/ic_launcher_beta.png deleted file mode 100644 index d70caab..0000000 Binary files a/app/src/main/res/mipmap-ldpi/ic_launcher_beta.png and /dev/null differ diff --git a/app/src/main/res/mipmap-ldpi/ic_launcher_round.png b/app/src/main/res/mipmap-ldpi/ic_launcher_round.png deleted file mode 100644 index 95f1bdb..0000000 Binary files a/app/src/main/res/mipmap-ldpi/ic_launcher_round.png and /dev/null differ diff --git a/app/src/main/res/mipmap-ldpi/ic_launcher_round_beta.png b/app/src/main/res/mipmap-ldpi/ic_launcher_round_beta.png deleted file mode 100644 index 81d73dd..0000000 Binary files a/app/src/main/res/mipmap-ldpi/ic_launcher_round_beta.png and /dev/null differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 2af2773..0000000 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_beta.png b/app/src/main/res/mipmap-mdpi/ic_launcher_beta.png deleted file mode 100644 index 06c9375..0000000 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_beta.png and /dev/null differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png deleted file mode 100644 index 7a5529b..0000000 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round_beta.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round_beta.png deleted file mode 100644 index e4748a9..0000000 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round_beta.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index d89940b..0000000 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_beta.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_beta.png deleted file mode 100644 index d3033d8..0000000 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_beta.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png deleted file mode 100644 index 61e94a5..0000000 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round_beta.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round_beta.png deleted file mode 100644 index b0f25c3..0000000 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round_beta.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index bededcf..0000000 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_beta.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_beta.png deleted file mode 100644 index 6e90849..0000000 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_beta.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png deleted file mode 100644 index 1ccec24..0000000 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round_beta.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round_beta.png deleted file mode 100644 index 4b589c2..0000000 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round_beta.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index ecc0dac..0000000 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_beta.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_beta.png deleted file mode 100644 index c322b8b..0000000 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_beta.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png deleted file mode 100644 index 6e0e0d6..0000000 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round_beta.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round_beta.png deleted file mode 100644 index 05dbd61..0000000 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round_beta.png and /dev/null differ diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml deleted file mode 100644 index dfa3218..0000000 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - BlackBox - 手动选择 - 选择应用 - 已安装应用 - 已安装模块 - 空空如也 - 过滤 - 开源地址 - XP管理 - 交流群 - 软件设置 - 权限设置 - 虚拟定位(预览版) - 真实位置 - 虚拟定位设置成功:%s-%s - 关闭虚拟定位 - 是否关闭 %s 的虚拟定位 - %s 已关闭虚拟定位 - 点击跳转到模块管理界面 - 模块管理 - 启用Xposed框架 - 伪装 - 隐藏Root - 隐藏Xposed框架 - 用户备注 - 确定 - 取消 - 停止运行 - 是否强行停止运行%s - %s已停止运行 - 清除数据 - 是否清除%s的数据? - 卸载应用 - 创建快捷方式 - 快捷方式名称 - 已尝试添加到桌面 - 若添加失败,请前往系统设置,为BlackBox打开"创建桌面快捷方式"的权限 - 不再提醒 - 安装成功 - 安装失败 : %s - 安装失败 - 卸载成功 - 卸载失败 - 卸载软件 - 是否卸载%s,卸载后相关数据将被清除? - 卸载模块 - 是否卸载该模块,卸载后将无法再发挥作用? - 移除成功 - 清除成功 - 启动失败 - 请在外部启动模块 - 重新启动软件修改才能生效 - 该桌面不支持创建快捷方式 - Xposed模块请在管理界面卸载 - 其它 - 开启守护进程 - GMS管理 - 跳转到GMS管理界面 - 开启服务 - 开启Google服务,可以让Youtube等强依赖Google Play Services的软件能正常运行。 - 关闭服务 - 是否清除当前Google服务环境?Google服务数据将被清空。 - 当前手机没有Google服务环境。 - \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml deleted file mode 100644 index 4df62cd..0000000 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ /dev/null @@ -1,65 +0,0 @@ - - BlackBox - 手動選擇 - 選擇應用程序 - 已安裝的應用程序 - 已安裝模塊 - 空的 - 篩檢 - 開源地址 - Xposed設定 - 電報組 - 虛擬定位(預覽) - 真實位置 - 成功設定虛擬定位:%s-%s - 禁用虛擬位置 - 是否關閉%s的虛擬定位 - 成功禁用%s的虛擬定位 - 軟件設定 - 轉到模塊管理器 - 模塊管理器 - 啟用Xposed框架 - 偽裝 - 隱藏Root - 隱藏Xposed - 用戶備註 - 確定 - 取消 - 許可權設定 - 不再提醒 - 停止運行 - 是否要強制停止%s? - %s已停止運行 - 清除數據 - 是否清除%s的數據? - 卸載應用程序 - 創建快捷方式 - 快捷方式名稱 - 嘗試添加到案頭 - 如果添加失敗,請轉到系統設置並打開BlackBox的“創建案頭快捷方式”許可權 - 安裝成功 - 安裝失敗:%s - 安裝失敗 - 已成功卸載 - 卸載失敗 - 卸載應用程序 - 是否卸載%s,卸載後相關資料將被清除? - 卸載模塊 - 是否要卸載此模塊? 卸載後它將不再工作? - 成功删除 - 成功清除 - 發射失敗 - 在外部啟動模塊 - 重新啟動應用程序以應用更改 - 此案頭不支持創建快捷方式 - 請在模塊管理器中卸載xposed模塊 - 其他 - 守護進程 - GMS管理 - 去找GMS管理 - 啟用服務 - 開放穀歌服務可以讓Youtube和其他高度依賴穀歌播放服務的軟件正常運行。 - 禁用服務 - 清除當前的穀歌服務環境? 穀歌服務數據將被清除。 - 現時,手機上沒有穀歌服務環境。 - \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml deleted file mode 100644 index 9facc85..0000000 --- a/app/src/main/res/values/colors.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - #3F3F3F - #3F3F3F - #3F3F3F - #ffffff - #212121 - #757575 - #FFFFFFFF - \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml deleted file mode 100644 index d4aa8b6..0000000 --- a/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - FridaBox - Choose - Choose App - Installed App - Installed Module - Empty - Filter - Open Source - Xposed Setting - Telegram Group - Fake Location(Preview) - Real Location - Set Fake Location Successfully:%s-%s - Disable FakeLocation - Disable FakeLocation for %s - Disable FakeLocation for %s Successfully - Setting - Go to Module Manager - Module Manager - Enable Xposed Framework - Hide - Hide Root - Hide Xposed - User Remark - Done - Cancel - Setting - No Reminders - Stop Running - Do you want to stop %s forcibly? - %s is Stopped - Clear Data - Clear Data for %s? - Uninstall App - Create Shortcut - Shortcut Name - Try Added To Desktop - If the addition fails, please go to system settings and open the permission of "create desktop shortcut" for BlackBox - Installed Successfully - Installed Failed: %s - Installed Failed - Uninstalled Successfully - Uninstalled Failed - Uninstall App - Uninstall %s, and relevant data will be cleared after uninstallation? - Uninstall Module - Do you want to uninstall this module? It will no longer work after uninstallation? - Removed Successfully - Cleared Successfully - Launched Failed - Start module in outside - Restart app to apply change - This desktop does not support creating shortcuts - Please uninstall the xposed module in the Module Manager - Others - Daemon - Use VPN Network - Route traffic through VPN for sandboxed apps (may improve network access) - Disable Flag Secure - Allow screenshots and screen recording in apps - GMS Manager - Go to Gms Manager - Enable Service - Opening Google services can make youtube and other software that strongly rely on Google play services run normally. - Disable Service - Clear the current Google service environment? Google service data will be cleared. - Currently, there is no Google service environment on mobile phones. - diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml deleted file mode 100644 index 4a7335f..0000000 --- a/app/src/main/res/values/themes.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml deleted file mode 100644 index dca93c0..0000000 --- a/app/src/main/res/xml/network_security_config.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/xml/setting.xml b/app/src/main/res/xml/setting.xml deleted file mode 100644 index 1d262a4..0000000 --- a/app/src/main/res/xml/setting.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/test/java/top/niunaijun/blackboxa/fridabox/ApkInspectorTest.java b/app/src/test/java/com/qm4rs/fridabox/ApkInspectorTest.java similarity index 97% rename from app/src/test/java/top/niunaijun/blackboxa/fridabox/ApkInspectorTest.java rename to app/src/test/java/com/qm4rs/fridabox/ApkInspectorTest.java index 9fbcb2c..30a4a45 100644 --- a/app/src/test/java/top/niunaijun/blackboxa/fridabox/ApkInspectorTest.java +++ b/app/src/test/java/com/qm4rs/fridabox/ApkInspectorTest.java @@ -1,4 +1,4 @@ -package top.niunaijun.blackboxa.fridabox; +package com.qm4rs.fridabox; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; diff --git a/app/src/test/java/top/niunaijun/blackboxa/fridabox/ApkIntegrityTest.java b/app/src/test/java/com/qm4rs/fridabox/ApkIntegrityTest.java similarity index 90% rename from app/src/test/java/top/niunaijun/blackboxa/fridabox/ApkIntegrityTest.java rename to app/src/test/java/com/qm4rs/fridabox/ApkIntegrityTest.java index 5119993..c7bfbd5 100644 --- a/app/src/test/java/top/niunaijun/blackboxa/fridabox/ApkIntegrityTest.java +++ b/app/src/test/java/com/qm4rs/fridabox/ApkIntegrityTest.java @@ -1,4 +1,4 @@ -package top.niunaijun.blackboxa.fridabox; +package com.qm4rs.fridabox; import static org.junit.Assert.assertEquals; diff --git a/app/src/test/java/top/niunaijun/blackboxa/fridabox/InstrumentationPreferenceParserTest.java b/app/src/test/java/com/qm4rs/fridabox/InstrumentationPreferenceParserTest.java similarity index 94% rename from app/src/test/java/top/niunaijun/blackboxa/fridabox/InstrumentationPreferenceParserTest.java rename to app/src/test/java/com/qm4rs/fridabox/InstrumentationPreferenceParserTest.java index bf0bce5..223f8eb 100644 --- a/app/src/test/java/top/niunaijun/blackboxa/fridabox/InstrumentationPreferenceParserTest.java +++ b/app/src/test/java/com/qm4rs/fridabox/InstrumentationPreferenceParserTest.java @@ -1,4 +1,4 @@ -package top.niunaijun.blackboxa.fridabox; +package com.qm4rs.fridabox; import static org.junit.Assert.assertEquals; diff --git a/docs/BASELINE.md b/docs/BASELINE.md index 397d060..166b669 100644 --- a/docs/BASELINE.md +++ b/docs/BASELINE.md @@ -1,6 +1,6 @@ -# NewBlackbox baseline +# FridaBox build baseline -- Foundation: `ALEX5402/NewBlackbox`, branch `main` +- Virtual runtime foundation revision: `89b59836c66f173756a4ae258cf379a957649820` - Required commit: `89b59836c66f173756a4ae258cf379a957649820` - Working branch: `feature/fridabox-mvp` - Baseline date: 2026-07-19 diff --git a/docs/TEST_RESULTS.md b/docs/TEST_RESULTS.md index 40e119a..defad76 100644 --- a/docs/TEST_RESULTS.md +++ b/docs/TEST_RESULTS.md @@ -55,8 +55,8 @@ baseline build investigation are recorded in `docs/BASELINE.md`. Runtime validation passed on a Samsung SM-S928B running ARM64 Android 16/API 36: - latest host APK installed successfully; -- the sample installed only in BlackBox and was absent from Android user 0's - real PackageManager; +- the sample installed only in the FridaBox private workspace and was absent + from Android user 0's real PackageManager; - Gadget paused startup before `SampleApplication.attachBaseContext` and `onCreate`; - the controller mapped port 27042 to the sample package/process and reported @@ -119,3 +119,28 @@ Artifacts: The release artifact was intentionally unsigned because no production keystore was supplied. `apksigner` confirmed the debug APK verifies and the release APK does not contain a debug signature. + +## Legacy shell removal validation + +Validation date: 2026-07-20 + +The obsolete launcher, GMS/Xposed/fake-location screens, legacy resources, +Chinese launcher translations, bundled UI AARs, and old product documentation +were removed. The application namespace and all host-owned source moved to +`com.qm4rs.fridabox`; only the runtime engine's compatibility API remains under +its upstream package namespace, with attribution retained in +`THIRD_PARTY_NOTICES.md`. + +The cleanup passed app/Bcore unit tests, debug and release assembly, and the +complete app lint/check task. On the connected Samsung SM-S928B (ARM64, +Android 16/API 36), the new APK installed successfully, resumed +`com.qm4rs.fridabox/.FridaBoxActivity`, restored both private guests, and launched +`com.paeezanstudio.pesarkhande` in Clean mode through `ProxyActivity$P0` without +a fatal exception. + +Final cleanup artifacts: + +- debug: 19,795,788 bytes, SHA-256 + `3fabf2887b3bf1aa1a83475b18803755168b33b2111e89f15d3d1434d89994a5`; +- release: 12,454,018 bytes, SHA-256 + `b7e9033def3fbe25f92686ceb3a3e2f623951e8d7fdd450b172d30df25e08e8e`. diff --git a/docs/device-validation.log b/docs/device-validation.log index ec982da..462aa91 100644 --- a/docs/device-validation.log +++ b/docs/device-validation.log @@ -265,3 +265,49 @@ BUILD SUCCESSFUL - release APK: 13266764 bytes, SHA-256 caa2218194fcbe91c10d0d29a74b7401aaed53f340b8a0d6668321ddae48ddfb - debug signature verification: passed - release signature verification: intentionally unsigned; no debug key fallback + +=== FridaBox-only application shell cleanup (2026-07-20) === + +> adb devices -l +R5CY149SZEX device product:e3qxxx model:SM_S928B device:e3q transport_id:1 + +> adb shell getprop ro.product.cpu.abi +arm64-v8a + +> adb shell getprop ro.build.version.release +16 + +> adb shell getprop ro.build.version.sdk +36 + +> $env:FRIDABOX_NDK_PROJECT_DIR='D:\FridaBoxBuild\Bcore'; .\gradlew.bat :app:assembleDebug :Bcore:testDebugUnitTest :app:testDebugUnitTest --console=plain '-Dkotlin.compiler.execution.strategy=in-process' +BUILD SUCCESSFUL in 46s + +> $env:FRIDABOX_NDK_PROJECT_DIR='D:\FridaBoxBuild\Bcore'; .\gradlew.bat :app:assembleRelease :app:check --console=plain '-Dkotlin.compiler.execution.strategy=in-process' +BUILD SUCCESSFUL in 2m 13s + +> adb install -r -t D:\Android Codes\FridaBox\app\build\outputs\apk\debug\FridaBox_4.0.0_arm64-v8a-debug.apk +Performing Streamed Install +Success + +> adb shell monkey -p com.qm4rs.fridabox -c android.intent.category.LAUNCHER 1 +Events injected: 1 + +> adb shell dumpsys activity activities +topResumedActivity=ActivityRecord{61631798 u0 com.qm4rs.fridabox/.FridaBoxActivity t2830} + +The UI hierarchy identified the host package as `com.qm4rs.fridabox`, displayed +the FridaBox product identity, and restored two private guests. The imported game +was switched to Clean mode and launched from its card. + +> adb shell dumpsys activity activities +topResumedActivity=ActivityRecord{234428585 u0 com.qm4rs.fridabox/top.niunaijun.blackbox.proxy.ProxyActivity$P0 t2831} + +No `FATAL EXCEPTION` or `AndroidRuntime` crash was emitted. The compatibility +activity class above belongs to the retained runtime engine; the host launcher, +application, namespace, source tree, and resources are FridaBox-owned. + +Final cleanup artifacts: + +- debug APK: 19795788 bytes, SHA-256 3fabf2887b3bf1aa1a83475b18803755168b33b2111e89f15d3d1434d89994a5 +- release APK: 12454018 bytes, SHA-256 b7e9033def3fbe25f92686ceb3a3e2f623951e8d7fdd450b172d30df25e08e8e diff --git a/settings.gradle b/settings.gradle index 794d96e..ef13195 100644 --- a/settings.gradle +++ b/settings.gradle @@ -33,7 +33,7 @@ dependencyResolutionManagement { } } -rootProject.name = "NewBlackbox" +rootProject.name = "FridaBox" include ':app' include(":black-reflection")