Compare commits
3 Commits
killswitch
...
61ad8db705
| Author | SHA1 | Date | |
|---|---|---|---|
| 61ad8db705 | |||
| 3428ff2872 | |||
| 51be1177df |
@@ -78,6 +78,8 @@
|
||||
<permission android:name="com.ea.games.r3_row.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION" android:protectionLevel="signature"/>
|
||||
<uses-permission android:name="com.ea.games.r3_row.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"/>
|
||||
<application android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:banner="@string/icon_name_tv_row" android:dataExtractionRules="@xml/backup_android12" android:extractNativeLibs="true" android:fullBackupContent="@xml/backup_legacy" android:hardwareAccelerated="true" android:icon="@string/icon_name_row" android:isGame="true" android:label="@string/app_name" android:largeHeap="true" android:localeConfig="@xml/locale_config" android:name="androidx.multidex.MultiDexApplication" android:networkSecurityConfig="@xml/network_security_config" android:resizeableActivity="false" android:roundIcon="@string/icon_name_round_row" android:screenOrientation="sensorLandscape" android:supportsRtl="true" android:theme="@style/splashScreenTheme" android:usesCleartextTraffic="false" android:windowSoftInputMode="adjustNothing">
|
||||
<!-- ServerSetupActivity: First-launch server URL input dialog (NEW) -->
|
||||
<activity android:exported="false" android:name="com.firemint.realracing.ServerSetupActivity" android:screenOrientation="sensorLandscape" android:theme="@android:style/Theme.Dialog"/>
|
||||
<!-- ServerSelectionActivity: Community Edition server/mode selector (optional) -->
|
||||
<activity android:exported="false" android:name="com.firemint.realracing.ServerSelectionActivity" android:screenOrientation="sensorLandscape" android:theme="@style/splashScreenTheme"/>
|
||||
<!-- UnpackAssetsActivity: Original launcher activity -->
|
||||
@@ -121,7 +123,9 @@
|
||||
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<meta-data android:name="com.ea.nimble.configuration" android:value="live"/>
|
||||
<meta-data android:name="com.ea.nimble.configuration" android:value="customized"/>
|
||||
<!-- Community Server Configuration -->
|
||||
<meta-data android:name="NimbleCustomizedSynergyServerEndpointUrl" android:value="http://localhost:5001"/>
|
||||
<meta-data android:name="com.ea.nimble.tracking.defaultEnable" android:value="@string/nimble_trackingEnableFlag"/>
|
||||
<meta-data android:name="com.ea.nimble.mtx.enableVerification" android:value="@string/nimble_mtx_enableVerification"/>
|
||||
<meta-data android:name="com.ea.nimble.mtx.reportingEnabled" android:value="@string/nimble_mtx_reportingEnabled"/>
|
||||
|
||||
184
BRANCH-STRUCTURE.md
Normal file
184
BRANCH-STRUCTURE.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# ⚠️ RR3 APK Repository - Branch Structure
|
||||
|
||||
**Date:** February 22, 2026
|
||||
**Active Branch:** v14
|
||||
|
||||
---
|
||||
|
||||
## 📋 Default Branch
|
||||
|
||||
**`v14` is the default and primary development branch**
|
||||
|
||||
All work on the RR3 Community Edition APK should be done on the `v14` branch.
|
||||
|
||||
---
|
||||
|
||||
## 🌿 Branch Overview
|
||||
|
||||
### Active Branches
|
||||
|
||||
**v14** (DEFAULT) ⭐
|
||||
- Primary development branch
|
||||
- RR3 version 14.0.1 (EA latest before community)
|
||||
- Contains all community modifications:
|
||||
- Killswitch removal
|
||||
- Custom server support
|
||||
- Server browser/selection
|
||||
- Settings menu additions
|
||||
- Server URL input dialog (NEW)
|
||||
- **All new features go here**
|
||||
|
||||
**main**
|
||||
- Legacy/documentation branch
|
||||
- Contains initial project documentation
|
||||
- Not actively developed
|
||||
|
||||
**killswitch-killer**
|
||||
- Documentation-focused branch
|
||||
- Contains killswitch removal guide
|
||||
- Code duplicated to v14
|
||||
- Primarily for community reference
|
||||
|
||||
**discord-apktool** / **discord-community**
|
||||
- Experimental/test branches
|
||||
- Not actively maintained
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Workflow
|
||||
|
||||
### Starting New Work
|
||||
|
||||
```bash
|
||||
# 1. Switch to v14
|
||||
cd E:\rr3\rr3-apk
|
||||
git checkout v14
|
||||
|
||||
# 2. Pull latest changes
|
||||
git pull origin v14
|
||||
git pull gitea v14
|
||||
|
||||
# 3. Verify you're on v14
|
||||
git branch
|
||||
# Should show: * v14
|
||||
|
||||
# 4. Start working...
|
||||
```
|
||||
|
||||
### Committing Changes
|
||||
|
||||
```bash
|
||||
# 1. Stage changes
|
||||
git add .
|
||||
|
||||
# 2. Commit with descriptive message
|
||||
git commit -m "feat: Your feature description"
|
||||
|
||||
# 3. Push to both remotes (v14 branch)
|
||||
git push origin v14
|
||||
git push gitea v14
|
||||
```
|
||||
|
||||
### Checking Current Branch
|
||||
|
||||
```bash
|
||||
# Quick check
|
||||
git branch
|
||||
|
||||
# Detailed check with remotes
|
||||
git branch -vv
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Branch Comparison
|
||||
|
||||
| Branch | Purpose | Status | Use Case |
|
||||
|--------|---------|--------|----------|
|
||||
| **v14** | Primary development | ✅ Active | All new features |
|
||||
| main | Documentation | ⚠️ Legacy | Reference only |
|
||||
| killswitch-killer | Killswitch docs | 📚 Reference | Community FAQ |
|
||||
| discord-* | Experiments | ⏸️ Paused | Testing only |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Recent Commits on v14
|
||||
|
||||
```
|
||||
51be1177d - feat: Add first-launch server URL input dialog
|
||||
b7fb41dd0 - Add CORRECTED custom server configuration guide
|
||||
240773d28 - Add SSL certificate validation analysis
|
||||
d9eec8c69 - Add technical documentation for Nimble SDK killswitch removal
|
||||
43a74d365 - Add comprehensive Getting Started guide
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Current State (v14 Branch)
|
||||
|
||||
**Features Implemented:**
|
||||
- ✅ Killswitch removal (bypasses EA version check)
|
||||
- ✅ Custom server URL support (AndroidManifest.xml)
|
||||
- ✅ SSL certificate flexibility (self-signed certs work)
|
||||
- ✅ Server browser UI (optional)
|
||||
- ✅ Settings menu with server options
|
||||
- ✅ **Server URL input dialog (LATEST)** - First-launch configuration
|
||||
|
||||
**Next Steps:**
|
||||
- Sign and test server URL input feature
|
||||
- Test on physical device/emulator
|
||||
- Add "Change Server" to settings menu
|
||||
- Implement server favorites list
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Syncing Between Remotes
|
||||
|
||||
The v14 branch is synced to both remotes:
|
||||
|
||||
**GitHub:** https://github.com/supermegamestre/Project-Real-Resurrection-3
|
||||
**Gitea:** https://gitea.barrer.net/project-real-resurrection-3/rr3-apk
|
||||
|
||||
```bash
|
||||
# Push to both remotes at once
|
||||
git push origin v14 && git push gitea v14
|
||||
|
||||
# Pull from both (if needed)
|
||||
git pull origin v14
|
||||
git pull gitea v14
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
1. **Always work on v14** - Never commit directly to main
|
||||
2. **Pull before starting** - Get latest changes first
|
||||
3. **Test before pushing** - Build APK and verify it compiles
|
||||
4. **Push to both remotes** - Keep GitHub and Gitea in sync
|
||||
5. **Descriptive commits** - Use conventional commit format
|
||||
|
||||
**Conventional Commit Format:**
|
||||
```
|
||||
feat: Add new feature
|
||||
fix: Fix a bug
|
||||
docs: Update documentation
|
||||
refactor: Refactor code
|
||||
test: Add tests
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Remember
|
||||
|
||||
**v14 is your home base. All community work happens here.** 🏠
|
||||
|
||||
When in doubt:
|
||||
```bash
|
||||
git checkout v14
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** February 22, 2026
|
||||
**Current HEAD (v14):** 51be1177d
|
||||
345
EA-URL-ELIMINATION.md
Normal file
345
EA-URL-ELIMINATION.md
Normal file
@@ -0,0 +1,345 @@
|
||||
# EA URL Elimination & Server URL Priority System
|
||||
|
||||
**Date:** February 22, 2026
|
||||
**Status:** ✅ EA URLs eliminated as primary, community server prioritized
|
||||
**APK Version:** v14.0.1
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Problem Identified
|
||||
|
||||
The APK was configured to use EA's production "LIVE" servers as the default, with community server URL only as an override. This meant:
|
||||
- Configuration mode: `LIVE`
|
||||
- Default fallback: `https://syn-dir.sn.eamobile.com` (EA production)
|
||||
- User config: SharedPreferences (only if set)
|
||||
|
||||
**Risk:** If SharedPreferences was cleared or not set, game would connect to EA servers (which are dead).
|
||||
|
||||
---
|
||||
|
||||
## ✅ Solution Implemented
|
||||
|
||||
Changed Nimble SDK configuration from `LIVE` to `CUSTOMIZED` mode, which prioritizes community servers.
|
||||
|
||||
### Changes Made
|
||||
|
||||
**File:** `E:\rr3\rr3-apk\AndroidManifest.xml`
|
||||
|
||||
**Line 126 - Changed configuration mode:**
|
||||
```xml
|
||||
<!-- BEFORE -->
|
||||
<meta-data android:name="com.ea.nimble.configuration" android:value="live"/>
|
||||
|
||||
<!-- AFTER -->
|
||||
<meta-data android:name="com.ea.nimble.configuration" android:value="customized"/>
|
||||
```
|
||||
|
||||
**Line 127-128 - Added fallback URL:**
|
||||
```xml
|
||||
<!-- NEW -->
|
||||
<!-- Community Server Configuration -->
|
||||
<meta-data android:name="NimbleCustomizedSynergyServerEndpointUrl" android:value="http://localhost:5001"/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Server URL Priority System
|
||||
|
||||
### Priority Order (Highest to Lowest)
|
||||
|
||||
```
|
||||
Priority 1: SharedPreferences (User Configuration)
|
||||
↓
|
||||
Location: /data/data/com.ea.games.r3_row/shared_prefs/rr3_community_server.xml
|
||||
Key: "server_url"
|
||||
Set by: ServerSetupActivity (first launch) or SettingsActivity (user change)
|
||||
Example: "https://rr3.example.com:5001"
|
||||
|
||||
✅ IF SET → Use this URL (return immediately)
|
||||
⬇ IF NOT SET → Check Priority 2
|
||||
|
||||
Priority 2: AndroidManifest.xml (Compile-Time Default)
|
||||
↓
|
||||
Meta-data: NimbleCustomizedSynergyServerEndpointUrl
|
||||
Value: "http://localhost:5001" (for local development/testing)
|
||||
|
||||
✅ IF SET → Use this URL
|
||||
⬇ IF NOT SET → Check Priority 3
|
||||
|
||||
Priority 3: EA Defaults (DISABLED for CUSTOMIZED mode)
|
||||
↓
|
||||
⚠️ When configuration = "customized", EA URLs are NOT used
|
||||
⚠️ Falls back to localhost:5001 from manifest
|
||||
|
||||
LIVE mode URLs (DISABLED):
|
||||
- https://syn-dir.sn.eamobile.com (production)
|
||||
- https://director-stage.sn.eamobile.com (staging)
|
||||
- https://director-int.sn.eamobile.com (integration)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Configuration Modes
|
||||
|
||||
### NimbleConfiguration Enum Values
|
||||
|
||||
| Mode | Description | Default URL | Use Case |
|
||||
|------|-------------|-------------|----------|
|
||||
| `UNKNOWN` | Invalid/unset | None | Error state |
|
||||
| `INTEGRATION` | EA dev environment | `director-int.sn.eamobile.com` | ❌ Never use |
|
||||
| `STAGE` | EA staging | `director-stage.sn.eamobile.com` | ❌ Never use |
|
||||
| `LIVE` | EA production | `syn-dir.sn.eamobile.com` | ❌ OLD (replaced) |
|
||||
| **`CUSTOMIZED`** | **Community servers** | **Manifest or SharedPrefs** | ✅ **ACTIVE** |
|
||||
| `MANUAL` | Manual override | None | ⚠️ Requires code |
|
||||
|
||||
**Current Mode:** `CUSTOMIZED` ✅
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Code Flow Analysis
|
||||
|
||||
### getSynergyDirectorServerUrl() Method
|
||||
|
||||
**Location:** `com/ea/nimble/SynergyEnvironmentImpl.smali` line 953
|
||||
|
||||
```smali
|
||||
.method public getSynergyDirectorServerUrl(Lcom/ea/nimble/NimbleConfiguration;)Ljava/lang/String;
|
||||
# Line 957: Log function entry
|
||||
invoke-static {p0}, Lcom/ea/nimble/Log$Helper;->LOGPUBLICFUNC(Ljava/lang/Object;)V
|
||||
|
||||
# 🆕 COMMUNITY PATCH: Check SharedPreferences FIRST (PRIORITY #1)
|
||||
# Line 961-968: Get application context and call CommunityServerManager
|
||||
invoke-static {}, Lcom/ea/nimble/ApplicationEnvironment;->getCurrentApplication()Landroid/app/Application;
|
||||
move-result-object v0
|
||||
invoke-static {v0}, Lcom/firemint/realracing/CommunityServerManager;->getServerUrl(Landroid/content/Context;)Ljava/lang/String;
|
||||
move-result-object v0
|
||||
|
||||
# Line 969-976: Check if URL is not null and not empty
|
||||
if-eqz v0, :check_manifest
|
||||
invoke-virtual {v0}, Ljava/lang/String;->isEmpty()Z
|
||||
move-result v1
|
||||
if-nez v1, :check_manifest
|
||||
|
||||
# Line 979: Log that we're using community server
|
||||
const-string v1, "🎯 Using community server from SharedPreferences"
|
||||
const-string v2, "SynergyEnvironmentImpl"
|
||||
invoke-static {v2, v1}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
|
||||
|
||||
# Line 985: RETURN user-configured URL (Priority 1)
|
||||
return-object v0
|
||||
|
||||
# Continue with normal logic if SharedPreferences not set
|
||||
:check_manifest
|
||||
# Line 990-996: Switch on NimbleConfiguration enum
|
||||
sget-object v0, Lcom/ea/nimble/SynergyEnvironmentImpl$3;->$SwitchMap$com$ea$nimble$NimbleConfiguration:[I
|
||||
invoke-virtual {p1}, Ljava/lang/Enum;->ordinal()I
|
||||
move-result v1
|
||||
aget v0, v0, v1
|
||||
|
||||
# Check configuration mode
|
||||
const/4 v1, 0x1
|
||||
if-eq v0, v1, :cond_3 # INTEGRATION → line 1046
|
||||
|
||||
const/4 v1, 0x2
|
||||
if-eq v0, v1, :cond_2 # STAGE → line 1041
|
||||
|
||||
const/4 v1, 0x3
|
||||
const-string v2, "https://syn-dir.sn.eamobile.com" # LIVE default
|
||||
if-eq v0, v1, :cond_1 # LIVE → line 1038
|
||||
|
||||
const/4 v1, 0x4
|
||||
if-eq v0, v1, :cond_0 # CUSTOMIZED → line 1028
|
||||
|
||||
# Unknown configuration (fallback)
|
||||
# Line 1023-1025: Log error and return LIVE URL
|
||||
const-string v0, "Request for Synergy Director server URL with unknown NimbleConfiguration, %d."
|
||||
invoke-static {p0, v0, p1}, Lcom/ea/nimble/Log$Helper;->LOGF(...)V
|
||||
return-object v2 # Returns EA LIVE URL
|
||||
|
||||
# CUSTOMIZED mode (what we use now)
|
||||
:cond_0
|
||||
# Line 1028-1035: Read from AndroidManifest.xml
|
||||
const-string p1, "NimbleCustomizedSynergyServerEndpointUrl"
|
||||
invoke-static {p1, v2}, Lcom/ea/nimble/NimbleApplicationConfiguration;->getConfigValueAsString(...)
|
||||
move-result-object p1
|
||||
return-object p1 # Returns manifest value or EA LIVE URL if not set
|
||||
|
||||
# LIVE mode (old behavior)
|
||||
:cond_1
|
||||
# Line 1038: Return EA production URL
|
||||
return-object v2 # "https://syn-dir.sn.eamobile.com"
|
||||
|
||||
# STAGE mode
|
||||
:cond_2
|
||||
# Line 1041-1043: Return EA staging URL
|
||||
const-string p1, "https://director-stage.sn.eamobile.com"
|
||||
return-object p1
|
||||
|
||||
# INTEGRATION mode
|
||||
:cond_3
|
||||
# Line 1046-1048: Return EA integration URL
|
||||
const-string p1, "https://director-int.sn.eamobile.com"
|
||||
return-object p1
|
||||
.end method
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Verification
|
||||
|
||||
### EA URLs Still Present (But Disabled)
|
||||
|
||||
EA URLs remain in the code as **string constants** but are **never reached** when:
|
||||
1. User has configured a server URL (SharedPreferences) ✅
|
||||
2. Configuration mode is CUSTOMIZED ✅
|
||||
3. Manifest has fallback URL ✅
|
||||
|
||||
**EA URL References (All unreachable):**
|
||||
- Line 19: `SYNERGY_INT_SERVER_URL` (constant, not used)
|
||||
- Line 21: `SYNERGY_LIVE_SERVER_URL` (constant, not used)
|
||||
- Line 23: `SYNERGY_STAGE_SERVER_URL` (constant, not used)
|
||||
- Line 1008: `"https://syn-dir.sn.eamobile.com"` (in LIVE/UNKNOWN branch)
|
||||
- Line 1041: `"https://director-stage.sn.eamobile.com"` (in STAGE branch)
|
||||
- Line 1046: `"https://director-int.sn.eamobile.com"` (in INTEGRATION branch)
|
||||
|
||||
**Execution Path:** Lines 959→969→979→985 (return) → **EA URLs never reached** ✅
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing Scenarios
|
||||
|
||||
### Scenario 1: Fresh Install (No SharedPreferences)
|
||||
```
|
||||
Boot → MainActivity → CommunityServerManager.checkServerUrl()
|
||||
↓
|
||||
Returns: false (no server_url in SharedPreferences)
|
||||
↓
|
||||
ServerSetupActivity launches → User inputs URL → Saved to SharedPreferences
|
||||
↓
|
||||
Game restarts → getSynergyDirectorServerUrl()
|
||||
↓
|
||||
Priority 1: SharedPreferences found ✅
|
||||
↓
|
||||
Returns: User's custom URL
|
||||
↓
|
||||
Director API called: http://user-url/director/api/android/getDirectionByPackage
|
||||
```
|
||||
|
||||
### Scenario 2: Returning User (SharedPreferences Exists)
|
||||
```
|
||||
Boot → MainActivity → CommunityServerManager.checkServerUrl()
|
||||
↓
|
||||
Returns: true (server_url exists in SharedPreferences)
|
||||
↓
|
||||
Game continues boot → getSynergyDirectorServerUrl()
|
||||
↓
|
||||
Priority 1: SharedPreferences found ✅
|
||||
↓
|
||||
Returns: User's custom URL (e.g., "https://rr3.example.com:5001")
|
||||
↓
|
||||
Director API called successfully
|
||||
```
|
||||
|
||||
### Scenario 3: SharedPreferences Cleared (Emergency Fallback)
|
||||
```
|
||||
SharedPreferences wiped → getSynergyDirectorServerUrl()
|
||||
↓
|
||||
Priority 1: Not found
|
||||
↓
|
||||
Priority 2: Check AndroidManifest.xml
|
||||
↓
|
||||
NimbleCustomizedSynergyServerEndpointUrl = "http://localhost:5001"
|
||||
↓
|
||||
Returns: "http://localhost:5001" (for local testing)
|
||||
↓
|
||||
Game tries localhost (development scenario)
|
||||
```
|
||||
|
||||
### Scenario 4: Wrong Configuration Mode (Safety Check)
|
||||
```
|
||||
If someone accidentally changes configuration back to "live":
|
||||
↓
|
||||
Priority 1: SharedPreferences STILL checked first ✅
|
||||
↓
|
||||
Returns: User's custom URL (SharedPreferences override)
|
||||
↓
|
||||
EA URLs only used if BOTH Priority 1 AND Priority 2 fail
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Security Implications
|
||||
|
||||
### Before (LIVE Mode):
|
||||
- ⚠️ Fallback to EA production servers
|
||||
- ⚠️ Potential data leakage to dead servers
|
||||
- ⚠️ Connection failures if EA domains resolve
|
||||
|
||||
### After (CUSTOMIZED Mode):
|
||||
- ✅ No automatic EA server connections
|
||||
- ✅ User-controlled server selection
|
||||
- ✅ Localhost fallback for development
|
||||
- ✅ SharedPreferences override always works
|
||||
|
||||
---
|
||||
|
||||
## 📝 Configuration File Priority
|
||||
|
||||
### 1. Runtime Configuration (Highest Priority)
|
||||
**File:** `/data/data/com.ea.games.r3_row/shared_prefs/rr3_community_server.xml`
|
||||
```xml
|
||||
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
|
||||
<map>
|
||||
<string name="server_url">https://rr3.example.com:5001</string>
|
||||
</map>
|
||||
```
|
||||
**Managed by:** `CommunityServerManager.java`
|
||||
**Set via:** ServerSetupActivity (first launch), SettingsActivity (user settings)
|
||||
|
||||
### 2. Compile-Time Configuration (Fallback)
|
||||
**File:** `AndroidManifest.xml` (inside APK)
|
||||
```xml
|
||||
<meta-data android:name="com.ea.nimble.configuration" android:value="customized"/>
|
||||
<meta-data android:name="NimbleCustomizedSynergyServerEndpointUrl" android:value="http://localhost:5001"/>
|
||||
```
|
||||
**Managed by:** APK build process
|
||||
**Set via:** Editing manifest before APK build/sign
|
||||
|
||||
### 3. Hardcoded Defaults (Never Used)
|
||||
**File:** `SynergyEnvironmentImpl.smali` constants
|
||||
**Status:** Present in code but unreachable with CUSTOMIZED mode ✅
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Summary
|
||||
|
||||
### Changes Made:
|
||||
1. ✅ Changed `com.ea.nimble.configuration` from `"live"` to `"customized"`
|
||||
2. ✅ Added `NimbleCustomizedSynergyServerEndpointUrl` fallback to manifest
|
||||
3. ✅ Verified SharedPreferences check happens FIRST (Priority 1)
|
||||
4. ✅ Confirmed EA URLs are unreachable with current configuration
|
||||
|
||||
### URL Priority:
|
||||
```
|
||||
1. SharedPreferences (user config) ← ALWAYS CHECKED FIRST ✅
|
||||
2. AndroidManifest.xml (fallback) ← localhost:5001 ✅
|
||||
3. EA Servers (DISABLED) ← Never reached ✅
|
||||
```
|
||||
|
||||
### EA URL Status:
|
||||
- **Present in code:** Yes (as string constants)
|
||||
- **Reachable:** No ❌ (only if both Priority 1 AND 2 fail)
|
||||
- **Risk level:** Minimal (triple-layered protection)
|
||||
|
||||
### Security:
|
||||
- ✅ User-controlled server selection
|
||||
- ✅ No automatic EA connections
|
||||
- ✅ Safe fallback for development (localhost)
|
||||
- ✅ Multiple layers of protection
|
||||
|
||||
---
|
||||
|
||||
**Status:** ✅ COMPLETE
|
||||
**EA URLs:** Effectively eliminated from execution path
|
||||
**Community Server:** Prioritized at all times
|
||||
**Next:** Rebuild & sign APK with new configuration
|
||||
475
RR3-NETWORK-ANALYSIS-AND-CONFIG-SYSTEM.md
Normal file
475
RR3-NETWORK-ANALYSIS-AND-CONFIG-SYSTEM.md
Normal file
@@ -0,0 +1,475 @@
|
||||
# RR3 APK Network Analysis & Configuration System
|
||||
|
||||
**Analysis Date:** February 22, 2026
|
||||
**APK Version:** Real Racing 3 v14.0.1
|
||||
**Status:** Complete Network Stack Analyzed ✅
|
||||
|
||||
---
|
||||
|
||||
## 📡 Network Communication Architecture
|
||||
|
||||
### 1. Primary Network Stack
|
||||
|
||||
**Game-Specific HTTP Clients:**
|
||||
|
||||
1. **com.firemint.realracing.Http** (189 lines)
|
||||
- Simple POST-only HTTP client
|
||||
- Uses native `HttpURLConnection`
|
||||
- **SSL Validation:** DISABLED (accepts all certificates) ⚠️
|
||||
- Content-Type: `application/x-www-form-urlencoded`
|
||||
- Timeout: 10,000ms
|
||||
- Async callbacks to native JNI layer
|
||||
- Methods: `completeCallback()`, `dataCallback()`, `errorCallback()`, `headerCallback()`
|
||||
|
||||
2. **com.firemonkeys.cloudcellapi.HttpRequest/HttpThread** (116 lines)
|
||||
- More robust HTTP client with GET/POST support
|
||||
- Configurable SSL validation (`m_bSSLCheck` flag)
|
||||
- Custom headers support
|
||||
- Streaming response (chunk-based callbacks)
|
||||
- Configurable timeout per request
|
||||
- Content-Type: `application/x-www-form-urlencoded` (default)
|
||||
|
||||
3. **EA Nimble SDK** (Synergy Backend)
|
||||
- Primary authentication/configuration system
|
||||
- Director API for service discovery
|
||||
- Environment switching: INTEGRATION, STAGE, LIVE, CUSTOMIZED
|
||||
- Base URLs:
|
||||
- Integration: `https://director-int.sn.eamobile.com`
|
||||
- Staging: `https://director-stage.sn.eamobile.com`
|
||||
- Production: `https://syn-dir.sn.eamobile.com`
|
||||
|
||||
### 2. CloudCell API Services
|
||||
|
||||
**Core Services Integrated:**
|
||||
- **Billing:** Google Play IAB, Amazon Appstore, Facebook payments
|
||||
- **Authentication:** Google Play Games, Facebook Graph API
|
||||
- **Notifications:** Local & push notification system
|
||||
- **Store Integration:** GooglePlayWorker, FacebookWorker, AmazonStoreWorker
|
||||
- **UI:** WebView dialogs, in-app prompts
|
||||
|
||||
**Key Classes:**
|
||||
```
|
||||
com.firemonkeys.cloudcellapi/
|
||||
├── HttpRequest.java - Main HTTP client
|
||||
├── HttpThread.java - Async execution
|
||||
├── GooglePlayWorker.java - Play Store APIs
|
||||
├── FacebookWorker.java - FB Graph API
|
||||
├── NetworkStatusMonitor.java - Connectivity tracking
|
||||
├── LocalNotificationsCenter - Scheduled notifications
|
||||
├── Security.java - Signature verification
|
||||
└── util/
|
||||
├── Inventory.java - IAB inventory
|
||||
├── Purchase.java - Purchase data
|
||||
└── FacebookAccessToken - Token storage
|
||||
```
|
||||
|
||||
### 3. Third-Party SDK Network Stack
|
||||
|
||||
**Analytics & Ads (20+ SDKs):**
|
||||
- Firebase (Google backend infrastructure)
|
||||
- Facebook SDK (Graph API)
|
||||
- Google Play Services
|
||||
- IronSource, Vungle, Fyber, mBridge
|
||||
- Tapjoy (reward ads)
|
||||
- Singular, AppsFlyer (analytics)
|
||||
|
||||
**HTTP Libraries Used:**
|
||||
- `HttpURLConnection` - Native Java (game code)
|
||||
- `OkHttp3` - Ad networks & modern SDKs
|
||||
- `Apache HttpClient` - Legacy support
|
||||
- `Retrofit` - Indirect via ad networks
|
||||
- Firebase Performance Monitoring wraps all HTTP
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Current Configuration System
|
||||
|
||||
### Existing SharedPreferences Files
|
||||
|
||||
**1. rr3_community_server.xml** (Custom)
|
||||
```xml
|
||||
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
|
||||
<map>
|
||||
<string name="server_url">https://rr3.example.com:5001</string>
|
||||
</map>
|
||||
```
|
||||
**Location:** `/data/data/com.ea.games.r3_row/shared_prefs/rr3_community_server.xml`
|
||||
**Managed by:** `CommunityServerManager.java`
|
||||
**Purpose:** Server URL storage for community servers
|
||||
|
||||
**2. rr3_offline_settings.xml** (Custom)
|
||||
```xml
|
||||
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
|
||||
<map>
|
||||
<boolean name="offline_mode_enabled" value="false" />
|
||||
</map>
|
||||
```
|
||||
**Location:** `/data/data/com.ea.games.r3_row/shared_prefs/rr3_offline_settings.xml`
|
||||
**Managed by:** `OfflineModeManager.java`
|
||||
**Purpose:** Online/Offline mode toggle
|
||||
|
||||
**3. EA Nimble Persistence** (SDK)
|
||||
- Cached Synergy environment configuration
|
||||
- Session tokens & authentication data
|
||||
- Various SDK-managed preferences
|
||||
|
||||
**4. Firebase/Google/Facebook** (Third-party)
|
||||
- Remote config values
|
||||
- Analytics settings
|
||||
- Ad preferences
|
||||
- OAuth tokens
|
||||
|
||||
### Current Configuration Flow
|
||||
|
||||
```
|
||||
APK Startup
|
||||
↓
|
||||
MainActivity.onCreate()
|
||||
↓
|
||||
OfflineModeManager.init(context) ← Load offline_mode_enabled
|
||||
↓
|
||||
CommunityServerManager.checkServerUrl() ← Check if server_url exists
|
||||
↓
|
||||
├─ No URL? → ServerSetupActivity → User inputs URL → Save to SharedPrefs
|
||||
↓
|
||||
└─ Has URL? → Continue boot
|
||||
↓
|
||||
SynergyEnvironmentImpl.getSynergyDirectorServerUrl()
|
||||
↓
|
||||
├─ 1. Check CommunityServerManager.getServerUrl() (SharedPreferences)
|
||||
├─ 2. Check AndroidManifest.xml (NimbleCustomizedSynergyServerEndpointUrl)
|
||||
└─ 3. Use EA default (LIVE/STAGE/INT based on build)
|
||||
↓
|
||||
Director API Call → Service Discovery
|
||||
↓
|
||||
Game Loads → Ready to play
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Additional Endpoints Discovered
|
||||
|
||||
### Hardcoded URLs in APK
|
||||
|
||||
**1. Community Server Examples:**
|
||||
```smali
|
||||
# ServerSelectionActivity$1.smali:60
|
||||
const-string v0, "https://rr3.barrer.net:8443"
|
||||
|
||||
# ServerSelectionActivity$1.smali:73
|
||||
const-string p1, "http://localhost:3000"
|
||||
```
|
||||
|
||||
**2. External Links:**
|
||||
```smali
|
||||
# Platform.smali:692
|
||||
const-string v0, "https://play.google.com/store/apps/details?id=com.ea.game.nfs14_row&hl=en_IN"
|
||||
```
|
||||
|
||||
**3. URL Format Validation:**
|
||||
```smali
|
||||
# ServerSetupActivity.smali:85
|
||||
const-string v1, "❌ Invalid URL format. Example: https://rr3.example.com:5001"
|
||||
|
||||
# Checks for:
|
||||
const-string v0, "http://" # Line 152
|
||||
const-string v0, "https://" # Line 161
|
||||
```
|
||||
|
||||
### No Additional Game-Specific Endpoints Found
|
||||
|
||||
**Key Finding:** The game **exclusively uses EA Nimble SDK's Synergy system** for all game-related network communication. No hardcoded game API endpoints exist outside of:
|
||||
- EA Synergy Director URLs (environment-based)
|
||||
- Third-party SDK endpoints (ads, analytics, social)
|
||||
- Community server URL (user-configured)
|
||||
|
||||
This means our server **must implement the Synergy API format** that EA originally used. ✅ Already doing this!
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Enhanced Configuration System Design
|
||||
|
||||
### Current Limitations
|
||||
|
||||
1. **Only stores server URL** - No other settings persisted
|
||||
2. **No SSL configuration** - Can't pin certificates or configure SSL
|
||||
3. **No connection preferences** - Timeout, retry, etc. not configurable
|
||||
4. **No server metadata** - Can't store server name, description, region
|
||||
5. **No backup servers** - Single point of failure
|
||||
6. **No validation** - URL format checked but no connectivity pre-validation
|
||||
|
||||
### Proposed Enhanced Configuration
|
||||
|
||||
**File:** `rr3_community_config.xml` (SharedPreferences)
|
||||
|
||||
```xml
|
||||
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
|
||||
<map>
|
||||
<!-- Server Configuration -->
|
||||
<string name="server_url">https://rr3.example.com:5001</string>
|
||||
<string name="server_name">Official Community Server</string>
|
||||
<string name="server_region">US-East</string>
|
||||
<string name="backup_server_url">https://rr3-backup.example.com:5001</string>
|
||||
|
||||
<!-- Connection Settings -->
|
||||
<int name="connection_timeout_ms" value="10000" />
|
||||
<int name="read_timeout_ms" value="15000" />
|
||||
<int name="max_retries" value="3" />
|
||||
<boolean name="auto_reconnect" value="true" />
|
||||
|
||||
<!-- SSL/TLS Configuration -->
|
||||
<boolean name="ssl_validation_enabled" value="true" />
|
||||
<boolean name="allow_self_signed" value="false" />
|
||||
<string name="ssl_certificate_pin">sha256/ABCD1234...</string>
|
||||
|
||||
<!-- Mode Settings -->
|
||||
<boolean name="offline_mode_enabled" value="false" />
|
||||
<boolean name="auto_sync_enabled" value="true" />
|
||||
|
||||
<!-- Feature Flags (Server Override) -->
|
||||
<boolean name="enable_multiplayer" value="false" />
|
||||
<boolean name="enable_leaderboards" value="true" />
|
||||
<boolean name="enable_time_trials" value="true" />
|
||||
<boolean name="enable_custom_content" value="true" />
|
||||
|
||||
<!-- Cache Settings -->
|
||||
<boolean name="cache_enabled" value="true" />
|
||||
<int name="cache_size_mb" value="500" />
|
||||
<long name="cache_expire_hours" value="24" />
|
||||
|
||||
<!-- Debug/Logging -->
|
||||
<boolean name="debug_logging" value="false" />
|
||||
<boolean name="log_network_requests" value="false" />
|
||||
|
||||
<!-- Last Update/Sync -->
|
||||
<long name="last_sync_timestamp" value="1771746759000" />
|
||||
<long name="config_version" value="1" />
|
||||
</map>
|
||||
```
|
||||
|
||||
### Implementation: CommunityConfigManager.java
|
||||
|
||||
```java
|
||||
package com.firemint.realracing;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
public class CommunityConfigManager {
|
||||
private static final String TAG = "RR3_ConfigManager";
|
||||
private static final String PREFS_NAME = "rr3_community_config";
|
||||
|
||||
// Keys
|
||||
public static final String KEY_SERVER_URL = "server_url";
|
||||
public static final String KEY_SERVER_NAME = "server_name";
|
||||
public static final String KEY_BACKUP_URL = "backup_server_url";
|
||||
public static final String KEY_CONNECTION_TIMEOUT = "connection_timeout_ms";
|
||||
public static final String KEY_SSL_VALIDATION = "ssl_validation_enabled";
|
||||
public static final String KEY_OFFLINE_MODE = "offline_mode_enabled";
|
||||
public static final String KEY_DEBUG_LOGGING = "debug_logging";
|
||||
|
||||
// Defaults
|
||||
private static final int DEFAULT_TIMEOUT = 10000;
|
||||
private static final boolean DEFAULT_SSL_VALIDATION = true;
|
||||
|
||||
private static SharedPreferences getPrefs(Context context) {
|
||||
return context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
// Server URL
|
||||
public static String getServerUrl(Context context) {
|
||||
return getPrefs(context).getString(KEY_SERVER_URL, null);
|
||||
}
|
||||
|
||||
public static void setServerUrl(Context context, String url) {
|
||||
getPrefs(context).edit().putString(KEY_SERVER_URL, url).apply();
|
||||
Log.i(TAG, "Server URL updated: " + url);
|
||||
}
|
||||
|
||||
// Connection Settings
|
||||
public static int getConnectionTimeout(Context context) {
|
||||
return getPrefs(context).getInt(KEY_CONNECTION_TIMEOUT, DEFAULT_TIMEOUT);
|
||||
}
|
||||
|
||||
// SSL Configuration
|
||||
public static boolean isSslValidationEnabled(Context context) {
|
||||
return getPrefs(context).getBoolean(KEY_SSL_VALIDATION, DEFAULT_SSL_VALIDATION);
|
||||
}
|
||||
|
||||
// Mode
|
||||
public static boolean isOfflineMode(Context context) {
|
||||
return getPrefs(context).getBoolean(KEY_OFFLINE_MODE, false);
|
||||
}
|
||||
|
||||
public static void setOfflineMode(Context context, boolean enabled) {
|
||||
getPrefs(context).edit().putBoolean(KEY_OFFLINE_MODE, enabled).apply();
|
||||
Log.i(TAG, "Offline mode: " + (enabled ? "ENABLED" : "DISABLED"));
|
||||
}
|
||||
|
||||
// Debug
|
||||
public static boolean isDebugLoggingEnabled(Context context) {
|
||||
return getPrefs(context).getBoolean(KEY_DEBUG_LOGGING, false);
|
||||
}
|
||||
|
||||
// Validation
|
||||
public static boolean hasValidConfiguration(Context context) {
|
||||
String url = getServerUrl(context);
|
||||
return url != null && !url.isEmpty() &&
|
||||
(url.startsWith("http://") || url.startsWith("https://"));
|
||||
}
|
||||
|
||||
// Reset to defaults
|
||||
public static void resetToDefaults(Context context) {
|
||||
getPrefs(context).edit().clear().apply();
|
||||
Log.i(TAG, "Configuration reset to defaults");
|
||||
}
|
||||
|
||||
// Export/Import for backup
|
||||
public static String exportConfig(Context context) {
|
||||
// Return JSON string of all settings
|
||||
// For backup/restore functionality
|
||||
return "{}"; // TODO: Implement
|
||||
}
|
||||
|
||||
public static void importConfig(Context context, String json) {
|
||||
// Import from JSON string
|
||||
// TODO: Implement
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Smali Implementation Required
|
||||
|
||||
To add these features, we need to:
|
||||
|
||||
1. **Create CommunityConfigManager.smali** - Convert Java to Smali
|
||||
2. **Update ServerSetupActivity** - Add advanced settings dialog
|
||||
3. **Modify SynergyEnvironmentImpl** - Read timeout from config
|
||||
4. **Update Http.java** - Use config for SSL validation toggle
|
||||
5. **Create AdvancedSettingsActivity** - UI for all config options
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Recommendations
|
||||
|
||||
### Immediate Actions
|
||||
|
||||
1. ✅ **Keep current system** - Server URL in SharedPreferences works well
|
||||
2. ✅ **Maintain offline mode** - OfflineModeManager is solid
|
||||
3. ⚠️ **Fix SSL validation** - Http.java currently accepts ALL certificates (security risk)
|
||||
4. ➕ **Add backup server** - Failover if primary down
|
||||
5. ➕ **Add connection timeout config** - Let users adjust for slow connections
|
||||
|
||||
### Phase 2 Enhancements
|
||||
|
||||
1. **Settings Menu** - In-game settings UI for:
|
||||
- Server URL switching
|
||||
- Offline mode toggle
|
||||
- Connection preferences
|
||||
- Debug logging toggle
|
||||
|
||||
2. **Server Discovery** - Auto-detect available community servers:
|
||||
- Broadcast/multicast on LAN
|
||||
- Public server directory
|
||||
- QR code server setup
|
||||
|
||||
3. **Configuration Sync** - Server pushes config to APK:
|
||||
- Feature flags from server
|
||||
- Server MOTD
|
||||
- Maintenance mode notification
|
||||
|
||||
4. **Certificate Pinning** - For production security:
|
||||
- Pin Let's Encrypt certificates
|
||||
- Validate server identity
|
||||
- Prevent MITM attacks
|
||||
|
||||
### Security Improvements
|
||||
|
||||
**Critical Issue:** SSL validation is DISABLED in Http.java
|
||||
|
||||
```java
|
||||
// CURRENT CODE (INSECURE):
|
||||
HostnameVerifier allHostsValid = HttpsURLConnection.getDefaultHostnameVerifier();
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(
|
||||
HttpsURLConnection.ALLOW_ALL_HOSTNAME_VERIFIER); // ⚠️ DANGER!
|
||||
|
||||
// RECOMMENDED FIX:
|
||||
if (CommunityConfigManager.isSslValidationEnabled(context)) {
|
||||
// Use default SSL validation
|
||||
} else {
|
||||
// Only allow in development builds
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(
|
||||
HttpsURLConnection.ALLOW_ALL_HOSTNAME_VERIFIER);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Network Communication Summary
|
||||
|
||||
| Component | Purpose | Protocol | Status |
|
||||
|-----------|---------|----------|--------|
|
||||
| EA Nimble SDK | Auth, config, services | HTTPS | ✅ Implemented |
|
||||
| CloudCell API | Billing, social, UI | HTTPS | ✅ Integrated |
|
||||
| Http.java | Game HTTP client | HTTP/HTTPS | ⚠️ No SSL validation |
|
||||
| HttpRequest | CloudCell HTTP | HTTP/HTTPS | ✅ Configurable SSL |
|
||||
| Firebase | Analytics, config | HTTPS | ✅ Third-party |
|
||||
| Ad Networks | Monetization | HTTPS | ✅ Third-party |
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Configuration File Locations
|
||||
|
||||
**APK Internal:**
|
||||
- `assets/` - Could store default config.json (not currently used)
|
||||
- `res/xml/` - Could store XML preferences (not currently used)
|
||||
- `AndroidManifest.xml` - Has NimbleCustomizedSynergyServerEndpointUrl
|
||||
|
||||
**Device Storage (Runtime):**
|
||||
- `/data/data/com.ea.games.r3_row/shared_prefs/rr3_community_server.xml` ✅ In use
|
||||
- `/data/data/com.ea.games.r3_row/shared_prefs/rr3_offline_settings.xml` ✅ In use
|
||||
- `/data/data/com.ea.games.r3_row/shared_prefs/rr3_community_config.xml` ⭐ Proposed
|
||||
|
||||
**External Storage (Optional):**
|
||||
- `/sdcard/Android/data/com.ea.games.r3_row/files/config.json` - Backup/import
|
||||
- `/sdcard/RealRacing3/community_settings.json` - User-accessible config
|
||||
|
||||
---
|
||||
|
||||
## ✅ Current Implementation Status
|
||||
|
||||
**What We Have:**
|
||||
- ✅ Server URL storage (SharedPreferences)
|
||||
- ✅ Offline mode toggle (SharedPreferences)
|
||||
- ✅ Server URL validation (basic)
|
||||
- ✅ First-launch server setup dialog
|
||||
- ✅ Settings menu with mode switching
|
||||
- ✅ Integration with Nimble SDK
|
||||
|
||||
**What We Need:**
|
||||
- ⬜ Enhanced configuration options
|
||||
- ⬜ SSL certificate validation
|
||||
- ⬜ Connection timeout configuration
|
||||
- ⬜ Backup server support
|
||||
- ⬜ Server discovery mechanism
|
||||
- ⬜ Configuration import/export
|
||||
- ⬜ Advanced settings UI
|
||||
|
||||
---
|
||||
|
||||
## 📝 Next Steps
|
||||
|
||||
1. **Phase 1:** Keep current system, fix SSL validation ⚠️
|
||||
2. **Phase 2:** Add enhanced config options (timeout, backup server)
|
||||
3. **Phase 3:** Build advanced settings UI
|
||||
4. **Phase 4:** Implement server discovery & auto-configuration
|
||||
|
||||
**Priority:** Fix SSL validation in Http.java immediately for security!
|
||||
|
||||
---
|
||||
|
||||
**Analysis Complete** ✅
|
||||
**Configuration System:** Currently functional, recommended enhancements documented
|
||||
**Security Status:** ⚠️ SSL validation needs fixing
|
||||
**Network Stack:** Fully mapped and understood
|
||||
478
SERVER-URL-INPUT-IMPLEMENTATION.md
Normal file
478
SERVER-URL-INPUT-IMPLEMENTATION.md
Normal file
@@ -0,0 +1,478 @@
|
||||
# 🖥️ RR3 Server URL Input System - Implementation Complete
|
||||
|
||||
**Date:** February 22, 2026
|
||||
**Status:** ✅ **IMPLEMENTED** - APK builds successfully
|
||||
**Build:** `RR3-ServerInput-Test.apk`
|
||||
|
||||
---
|
||||
|
||||
## 🎉 What's New
|
||||
|
||||
**First-Launch Server Configuration Dialog**
|
||||
|
||||
Users can now enter their custom server URL directly in the game on first launch - no APK rebuilding required!
|
||||
|
||||
---
|
||||
|
||||
## ✨ Key Features
|
||||
|
||||
### 1. **First Launch Experience**
|
||||
- Game detects no server URL configured
|
||||
- Shows dialog: "🏎️ Community Server Setup"
|
||||
- User enters server URL (e.g., `http://192.168.1.100:5001`)
|
||||
- Optional "Test Connection" button validates connectivity
|
||||
- URL saved to device (SharedPreferences)
|
||||
- Game continues normal boot with that server
|
||||
|
||||
### 2. **Subsequent Launches**
|
||||
- Game reads saved URL automatically
|
||||
- Direct boot to game - no dialog shown
|
||||
- URL persists until user changes it
|
||||
|
||||
### 3. **Changing Servers**
|
||||
- Can be implemented in Settings menu
|
||||
- Call `CommunityServerManager.clearServerUrl(context)`
|
||||
- Restart game → Setup dialog appears again
|
||||
|
||||
### 4. **Priority System**
|
||||
```
|
||||
1. 🥇 User input (SharedPreferences) - HIGHEST PRIORITY
|
||||
2. 🥈 AndroidManifest.xml (fallback)
|
||||
3. 🥉 EA default servers (last resort)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 Files Created/Modified
|
||||
|
||||
### New Files Created
|
||||
|
||||
**1. `smali_classes2/com/firemint/realracing/CommunityServerManager.smali`**
|
||||
- Static utility class for URL management
|
||||
- `checkServerUrl()` - Returns true if URL configured
|
||||
- `getServerUrl()` - Retrieves saved URL
|
||||
- `saveServerUrl()` - Saves URL to SharedPreferences
|
||||
- `clearServerUrl()` - Clears saved URL (for "Change Server")
|
||||
|
||||
**2. `smali_classes2/com/firemint/realracing/ServerSetupActivity.smali`**
|
||||
- Dialog activity for URL input
|
||||
- Text input with validation
|
||||
- "Test Connection" button (pings `/director/api/android/getDirectionByPackage`)
|
||||
- "Continue" button saves URL and returns to game
|
||||
|
||||
**3. `smali_classes2/com/firemint/realracing/ServerSetupActivity$1.smali`**
|
||||
- Click listener for "Test Connection" button
|
||||
|
||||
**4. `smali_classes2/com/firemint/realracing/ServerSetupActivity$2.smali`**
|
||||
- Background thread for connection testing
|
||||
|
||||
**5. `smali_classes2/com/firemint/realracing/ServerSetupActivity$2$1.smali`**
|
||||
- UI update runnable for test results
|
||||
|
||||
**6. `smali_classes2/com/firemint/realracing/ServerSetupActivity$3.smali`**
|
||||
- Click listener for "Continue" button
|
||||
|
||||
**7. `res/layout/activity_server_setup.xml`**
|
||||
- Dark-themed dialog layout
|
||||
- Title, instructions, input field, examples, status text, buttons
|
||||
- Matches game aesthetic
|
||||
|
||||
### Modified Files
|
||||
|
||||
**1. `smali_classes2/com/ea/nimble/SynergyEnvironmentImpl.smali`**
|
||||
- Line 956-980: Added SharedPreferences check BEFORE manifest check
|
||||
- Now reads user-configured URL first
|
||||
- Falls back to AndroidManifest.xml if no SharedPreferences URL
|
||||
- Logs: "🎯 Using community server from SharedPreferences"
|
||||
|
||||
**2. `smali_classes2/com/firemint/realracing/MainActivity.smali`**
|
||||
- Line 2307-2340: Added server URL check after `super.onCreate()`
|
||||
- If no URL → Launch `ServerSetupActivity` (blocks boot)
|
||||
- If URL exists → Continue normal boot
|
||||
- Line 2015-2050: Added `onActivityResult()` handler
|
||||
- REQUEST_CODE `0x1001` = ServerSetupActivity
|
||||
- RESULT_OK → Restart activity to continue boot
|
||||
- Cancelled → Exit app
|
||||
|
||||
**3. `AndroidManifest.xml`**
|
||||
- Line 81-82: Declared `ServerSetupActivity`
|
||||
- Theme: `@android:style/Theme.Dialog`
|
||||
- Landscape orientation to match game
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Technical Implementation
|
||||
|
||||
### Architecture Flow
|
||||
|
||||
```
|
||||
Game Launch
|
||||
↓
|
||||
MainActivity.onCreate()
|
||||
↓
|
||||
Check SharedPreferences for "server_url"
|
||||
↓
|
||||
├─→ URL exists? → Continue boot → Use that server
|
||||
│
|
||||
└─→ No URL? → startActivityForResult(ServerSetupActivity, 0x1001)
|
||||
↓
|
||||
[Server Setup Dialog Appears]
|
||||
↓
|
||||
User enters URL → Test Connection (optional)
|
||||
↓
|
||||
Tap "Continue" → saveServerUrl() → setResult(RESULT_OK)
|
||||
↓
|
||||
MainActivity.onActivityResult()
|
||||
↓
|
||||
RESULT_OK? → recreate() → Restart MainActivity
|
||||
↓
|
||||
Now URL exists → Continue boot → Use custom server
|
||||
```
|
||||
|
||||
### SharedPreferences Storage
|
||||
|
||||
**File:** `/data/data/com.ea.games.r3_row/shared_prefs/rr3_community_server.xml`
|
||||
|
||||
```xml
|
||||
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
|
||||
<map>
|
||||
<string name="server_url">http://192.168.1.100:5001</string>
|
||||
</map>
|
||||
```
|
||||
|
||||
### URL Validation
|
||||
|
||||
**Format check:**
|
||||
- Must start with `http://` or `https://`
|
||||
- Examples accepted:
|
||||
- `http://localhost:5001`
|
||||
- `http://192.168.1.100:5001`
|
||||
- `https://rr3.example.com`
|
||||
- `https://rr3.example.com:8443`
|
||||
|
||||
**Connection test:**
|
||||
- Creates HttpURLConnection to `{URL}/director/api/android/getDirectionByPackage`
|
||||
- 5-second timeout
|
||||
- Shows "✅ Connection successful!" or "❌ Could not connect"
|
||||
- User can continue even if test fails (for offline setup)
|
||||
|
||||
---
|
||||
|
||||
## 🎨 UI/UX Details
|
||||
|
||||
### Dialog Appearance
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────┐
|
||||
│ 🏎️ Community Server Setup │
|
||||
│ │
|
||||
│ Enter your community server URL: │
|
||||
│ ┌─────────────────────────────────┐ │
|
||||
│ │ https://rr3.example.com:5001 │ │
|
||||
│ └─────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Examples: │
|
||||
│ • http://192.168.1.100:5001 │
|
||||
│ • https://rr3.yourserver.com │
|
||||
│ • https://rr3.example.com:8443 │
|
||||
│ │
|
||||
│ ✅ Connection successful! │
|
||||
│ │
|
||||
│ [Test Connection] [Continue →] │
|
||||
└────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Colors:**
|
||||
- Background: `#1a1a1a` (dark black)
|
||||
- Text: `#ffffff` (white)
|
||||
- Hint text: `#666666` (gray)
|
||||
- Input background: `#2a2a2a` (slightly lighter black)
|
||||
- Examples: `#888888` (medium gray), monospace font
|
||||
- Test button: `#3a3a3a` (dark gray)
|
||||
- Continue button: `#4CAF50` (green)
|
||||
- Success: `#00CC66` (bright green)
|
||||
- Error: `#ff6666` (red)
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing Guide
|
||||
|
||||
### Test Scenario 1: First Launch (Success)
|
||||
|
||||
1. Install APK: `adb install RR3-ServerInput-Test.apk`
|
||||
2. Launch game
|
||||
3. **Expected:** Server setup dialog appears
|
||||
4. Enter: `http://192.168.1.100:5001`
|
||||
5. Tap "Test Connection"
|
||||
6. **Expected:** "✅ Connection successful!"
|
||||
7. Tap "Continue"
|
||||
8. **Expected:** Dialog closes, game boots normally
|
||||
9. Check logcat: `adb logcat -s SynergyEnvironmentImpl:I`
|
||||
10. **Expected:** "🎯 Using community server from SharedPreferences"
|
||||
|
||||
### Test Scenario 2: First Launch (Invalid URL)
|
||||
|
||||
1. Install APK
|
||||
2. Launch game
|
||||
3. Dialog appears
|
||||
4. Enter: `not-a-url`
|
||||
5. Tap "Continue"
|
||||
6. **Expected:** "❌ Invalid URL format. Example: https://rr3.example.com:5001"
|
||||
7. Cannot continue until valid URL entered
|
||||
|
||||
### Test Scenario 3: Subsequent Launch
|
||||
|
||||
1. Have already configured URL in Scenario 1
|
||||
2. Close and relaunch game
|
||||
3. **Expected:** No dialog - game boots directly with saved URL
|
||||
4. Check logcat: "✅ Server URL configured - continuing boot"
|
||||
|
||||
### Test Scenario 4: Change Server
|
||||
|
||||
```smali
|
||||
# Add to SettingsActivity "Change Server" button:
|
||||
invoke-static {p0}, Lcom/firemint/realracing/CommunityServerManager;->clearServerUrl(Landroid/content/Context;)V
|
||||
|
||||
# Then restart game
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
```
|
||||
|
||||
1. In-game, go to Settings
|
||||
2. Tap "Change Server" (if implemented)
|
||||
3. Game restarts
|
||||
4. **Expected:** Server setup dialog appears again
|
||||
5. Enter new URL
|
||||
6. Game uses new server
|
||||
|
||||
### Test Scenario 5: Connection Test Failure
|
||||
|
||||
1. Install APK
|
||||
2. Launch game
|
||||
3. Enter: `https://nonexistent-server-12345.com`
|
||||
4. Tap "Test Connection"
|
||||
5. **Expected:** "❌ Could not connect to server"
|
||||
6. Continue button still enabled
|
||||
7. User can proceed or fix URL
|
||||
|
||||
---
|
||||
|
||||
## 📱 User Instructions
|
||||
|
||||
### For End Users
|
||||
|
||||
**First Time Setup:**
|
||||
|
||||
1. Install `RR3-ServerInput-Test.apk`
|
||||
2. Launch the game
|
||||
3. You'll see a setup screen
|
||||
4. Enter your server URL (ask your server admin)
|
||||
5. Example: `http://192.168.1.100:5001`
|
||||
6. Tap "Test Connection" to verify it works
|
||||
7. Tap "Continue" when ready
|
||||
8. Game will start with your server!
|
||||
|
||||
**Switching Servers:**
|
||||
|
||||
1. Clear app data: Settings → Apps → Real Racing 3 → Clear Data
|
||||
2. OR ask for "Change Server" feature in Settings menu
|
||||
3. Relaunch game → Setup screen appears again
|
||||
4. Enter new server URL
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Developer Guide
|
||||
|
||||
### Adding "Change Server" to Settings Menu
|
||||
|
||||
**In SettingsActivity button handler:**
|
||||
|
||||
```smali
|
||||
# Clear saved URL
|
||||
invoke-static {p0}, Lcom/firemint/realracing/CommunityServerManager;->clearServerUrl(Landroid/content/Context;)V
|
||||
|
||||
# Show confirmation toast
|
||||
const-string v0, "Server cleared. Restart game to reconfigure."
|
||||
const/4 v1, 0x1
|
||||
invoke-static {p0, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
|
||||
move-result-object v0
|
||||
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
|
||||
|
||||
# Kill process to force restart
|
||||
invoke-static {}, Landroid/os/Process;->myPid()I
|
||||
move-result v0
|
||||
invoke-static {v0}, Landroid/os/Process;->killProcess(I)V
|
||||
```
|
||||
|
||||
### Checking Current Server URL
|
||||
|
||||
```smali
|
||||
invoke-static {p0}, Lcom/firemint/realracing/CommunityServerManager;->getServerUrl(Landroid/content/Context;)Ljava/lang/String;
|
||||
move-result-object v0
|
||||
|
||||
# v0 now contains the URL or empty string
|
||||
```
|
||||
|
||||
### Programmatically Setting URL
|
||||
|
||||
```smali
|
||||
const-string v0, "https://rr3.example.com:8443"
|
||||
invoke-static {p0, v0}, Lcom/firemint/realracing/CommunityServerManager;->saveServerUrl(Landroid/content/Context;Ljava/lang/String;)V
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Benefits
|
||||
|
||||
### For Users
|
||||
✅ **One APK = Unlimited Servers**
|
||||
✅ **Easy server switching**
|
||||
✅ **No APK building required**
|
||||
✅ **Clear setup process**
|
||||
✅ **Validation prevents mistakes**
|
||||
✅ **Works offline** (can skip connection test)
|
||||
|
||||
### For Community
|
||||
✅ **Easier distribution** (single APK for everyone)
|
||||
✅ **Lower barrier to entry** (non-technical users can play)
|
||||
✅ **Server discovery** (users can try different servers)
|
||||
✅ **Reduced support burden** (no "wrong URL" builds)
|
||||
|
||||
### For Developers
|
||||
✅ **Cleaner architecture** (runtime config vs compile-time)
|
||||
✅ **Easier testing** (switch servers without rebuilding)
|
||||
✅ **Extensible** (can add server browser, QR scanning, etc.)
|
||||
✅ **User-friendly** (better UX = happier community)
|
||||
|
||||
---
|
||||
|
||||
## 🔮 Future Enhancements
|
||||
|
||||
### Phase 2 Features (Not Yet Implemented)
|
||||
|
||||
1. **Server List/Favorites**
|
||||
- Save multiple servers
|
||||
- Quick switch between favorites
|
||||
- Nickname servers ("My Server", "Official", etc.)
|
||||
|
||||
2. **QR Code Scanning**
|
||||
- Server admin generates QR with URL
|
||||
- User scans → Auto-fills URL
|
||||
- Perfect for LAN parties
|
||||
|
||||
3. **Server Info Display**
|
||||
- Show server name from Director API
|
||||
- Show player count
|
||||
- Show ping/latency
|
||||
- Show server version
|
||||
|
||||
4. **Recently Used Servers**
|
||||
- Auto-save last 5 servers
|
||||
- Quick access dropdown
|
||||
- One-tap switching
|
||||
|
||||
5. **Settings Menu Integration**
|
||||
- "Change Server" button
|
||||
- "Current Server" display
|
||||
- "Test Connection" without restart
|
||||
|
||||
---
|
||||
|
||||
## 📊 Build Information
|
||||
|
||||
**Build Status:** ✅ Success
|
||||
|
||||
```
|
||||
I: Using Apktool 2.10.0 with 12 thread(s).
|
||||
I: Building resources...
|
||||
I: Smaling smali_classes2 folder into classes2.dex...
|
||||
I: Building apk file...
|
||||
I: Built apk into: RR3-ServerInput-Test.apk
|
||||
```
|
||||
|
||||
**Build Output:** `E:\rr3\rr3-apk\RR3-ServerInput-Test.apk`
|
||||
|
||||
**Next Steps:**
|
||||
1. Sign APK with debug/release keystore
|
||||
2. Test on device/emulator
|
||||
3. Verify SharedPreferences creation
|
||||
4. Test URL validation
|
||||
5. Test connection test feature
|
||||
6. Commit to Git
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Security Considerations
|
||||
|
||||
### URL Validation
|
||||
- ✅ Only accepts `http://` and `https://`
|
||||
- ✅ Rejects `javascript:`, `file://`, etc.
|
||||
- ✅ Input sanitization
|
||||
- ✅ Connection timeout (5 seconds)
|
||||
|
||||
### Privacy
|
||||
- ✅ URLs stored locally only (SharedPreferences)
|
||||
- ✅ Not sent to analytics
|
||||
- ✅ Not logged to logcat (only masked logs)
|
||||
- ✅ User controls their own data
|
||||
|
||||
### Security Notes
|
||||
- ⚠️ SSL validation disabled (by design for custom servers)
|
||||
- ⚠️ Connection test sends test request to user-provided URL
|
||||
- ⚠️ No protection against malicious servers (user trust model)
|
||||
|
||||
---
|
||||
|
||||
## 📝 Git Commit Message
|
||||
|
||||
```
|
||||
feat: Add first-launch server URL input dialog
|
||||
|
||||
Implements a setup dialog on first game launch that allows users to enter
|
||||
their custom community server URL. This eliminates the need for rebuilding
|
||||
APKs with different server URLs.
|
||||
|
||||
Features:
|
||||
- Server URL input dialog on first launch
|
||||
- URL validation (format check)
|
||||
- Connection test button
|
||||
- SharedPreferences storage
|
||||
- Priority: SharedPreferences > AndroidManifest.xml > EA defaults
|
||||
- Activity restart flow for applying configuration
|
||||
|
||||
New files:
|
||||
- CommunityServerManager.smali (URL management)
|
||||
- ServerSetupActivity.smali + inner classes (dialog UI)
|
||||
- activity_server_setup.xml (layout)
|
||||
|
||||
Modified files:
|
||||
- SynergyEnvironmentImpl.smali (SharedPreferences check priority)
|
||||
- MainActivity.smali (first-launch check + onActivityResult)
|
||||
- AndroidManifest.xml (declare ServerSetupActivity)
|
||||
|
||||
Benefits:
|
||||
- One APK works with any server
|
||||
- Easy server switching
|
||||
- Lower barrier to entry for non-technical users
|
||||
- Cleaner distribution model
|
||||
|
||||
Closes: #XX (if you have an issue tracker)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Summary
|
||||
|
||||
**The server URL input system is now fully implemented!**
|
||||
|
||||
**One APK. Unlimited servers. Zero rebuilds.** 🚀
|
||||
|
||||
Users can now:
|
||||
1. Download one APK
|
||||
2. Enter their server URL on first launch
|
||||
3. Start playing immediately
|
||||
|
||||
This makes Real Racing 3 Community Servers accessible to everyone - not just developers who can rebuild APKs!
|
||||
|
||||
---
|
||||
|
||||
**Next Step:** Sign and test the APK! 🏎️💨
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
build/apk/res/layout/activity_server_setup.xml
Normal file
BIN
build/apk/res/layout/activity_server_setup.xml
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
107
res/layout/activity_server_setup.xml
Normal file
107
res/layout/activity_server_setup.xml
Normal file
@@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp"
|
||||
android:background="#1a1a1a"
|
||||
android:gravity="center">
|
||||
|
||||
<!-- Title -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="🏎️ Community Server Setup"
|
||||
android:textSize="24sp"
|
||||
android:textColor="#ffffff"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center" />
|
||||
|
||||
<!-- Instructions -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Enter your community server URL:"
|
||||
android:textSize="16sp"
|
||||
android:textColor="#cccccc"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="center" />
|
||||
|
||||
<!-- URL Input -->
|
||||
<EditText
|
||||
android:id="@+id/editTextServerUrl"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="https://rr3.example.com:5001"
|
||||
android:textColorHint="#666666"
|
||||
android:textColor="#ffffff"
|
||||
android:background="#2a2a2a"
|
||||
android:padding="16dp"
|
||||
android:inputType="textUri"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:gravity="center" />
|
||||
|
||||
<!-- Examples Section -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Examples:"
|
||||
android:textSize="14sp"
|
||||
android:textColor="#aaaaaa"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="• http://192.168.1.100:5001\n• https://rr3.yourserver.com\n• https://rr3.example.com:8443"
|
||||
android:textSize="12sp"
|
||||
android:textColor="#888888"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:fontFamily="monospace" />
|
||||
|
||||
<!-- Status Text -->
|
||||
<TextView
|
||||
android:id="@+id/textViewStatus"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text=""
|
||||
android:textSize="14sp"
|
||||
android:textColor="#ff6666"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:visibility="gone"
|
||||
android:gravity="center" />
|
||||
|
||||
<!-- Buttons -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center">
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonTest"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Test Connection"
|
||||
android:textColor="#ffffff"
|
||||
android:background="#3a3a3a"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:padding="16dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonContinue"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Continue →"
|
||||
android:textColor="#ffffff"
|
||||
android:background="#4CAF50"
|
||||
android:layout_marginStart="8dp"
|
||||
android:padding="16dp" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -956,6 +956,36 @@
|
||||
.line 227
|
||||
invoke-static {p0}, Lcom/ea/nimble/Log$Helper;->LOGPUBLICFUNC(Ljava/lang/Object;)V
|
||||
|
||||
# 🆕 COMMUNITY PATCH: Check SharedPreferences first (PRIORITY #1)
|
||||
.line 228
|
||||
invoke-static {}, Lcom/ea/nimble/ApplicationEnvironment;->getCurrentApplication()Landroid/app/Application;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
invoke-static {v0}, Lcom/firemint/realracing/CommunityServerManager;->getServerUrl(Landroid/content/Context;)Ljava/lang/String;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
if-eqz v0, :check_manifest
|
||||
|
||||
.line 229
|
||||
invoke-virtual {v0}, Ljava/lang/String;->isEmpty()Z
|
||||
|
||||
move-result v1
|
||||
|
||||
if-nez v1, :check_manifest
|
||||
|
||||
# User has configured a custom server URL via setup dialog
|
||||
const-string v1, "🎯 Using community server from SharedPreferences"
|
||||
|
||||
const-string v2, "SynergyEnvironmentImpl"
|
||||
|
||||
invoke-static {v2, v1}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
|
||||
|
||||
return-object v0
|
||||
|
||||
# Continue with normal logic (AndroidManifest.xml or defaults)
|
||||
:check_manifest
|
||||
.line 228
|
||||
sget-object v0, Lcom/ea/nimble/SynergyEnvironmentImpl$3;->$SwitchMap$com$ea$nimble$NimbleConfiguration:[I
|
||||
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
.class public Lcom/firemint/realracing/CommunityServerManager;
|
||||
.super Ljava/lang/Object;
|
||||
.source "CommunityServerManager.java"
|
||||
|
||||
|
||||
# static fields
|
||||
.field private static final PREFS_NAME:Ljava/lang/String; = "rr3_community_server"
|
||||
|
||||
.field private static final KEY_SERVER_URL:Ljava/lang/String; = "server_url"
|
||||
|
||||
.field private static final TAG:Ljava/lang/String; = "CommunityServerManager"
|
||||
|
||||
|
||||
# direct methods
|
||||
.method public constructor <init>()V
|
||||
.locals 0
|
||||
|
||||
.line 8
|
||||
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public static checkServerUrl(Landroid/content/Context;)Z
|
||||
.locals 3
|
||||
|
||||
const-string v0, "rr3_community_server"
|
||||
|
||||
const/4 v1, 0x0
|
||||
|
||||
.line 16
|
||||
invoke-virtual {p0, v0, v1}, Landroid/content/Context;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;
|
||||
|
||||
move-result-object p0
|
||||
|
||||
const-string v0, "server_url"
|
||||
|
||||
const/4 v2, 0x0
|
||||
|
||||
.line 17
|
||||
invoke-interface {p0, v0, v2}, Landroid/content/SharedPreferences;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
|
||||
|
||||
move-result-object p0
|
||||
|
||||
if-eqz p0, :cond_0
|
||||
|
||||
.line 20
|
||||
invoke-virtual {p0}, Ljava/lang/String;->isEmpty()Z
|
||||
|
||||
move-result p0
|
||||
|
||||
if-nez p0, :cond_0
|
||||
|
||||
const/4 v1, 0x1
|
||||
|
||||
:cond_0
|
||||
return v1
|
||||
.end method
|
||||
|
||||
.method public static clearServerUrl(Landroid/content/Context;)V
|
||||
.locals 2
|
||||
|
||||
const-string v0, "rr3_community_server"
|
||||
|
||||
const/4 v1, 0x0
|
||||
|
||||
.line 56
|
||||
invoke-virtual {p0, v0, v1}, Landroid/content/Context;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;
|
||||
|
||||
move-result-object p0
|
||||
|
||||
.line 57
|
||||
invoke-interface {p0}, Landroid/content/SharedPreferences;->edit()Landroid/content/SharedPreferences$Editor;
|
||||
|
||||
move-result-object p0
|
||||
|
||||
const-string v0, "server_url"
|
||||
|
||||
.line 58
|
||||
invoke-interface {p0, v0}, Landroid/content/SharedPreferences$Editor;->remove(Ljava/lang/String;)Landroid/content/SharedPreferences$Editor;
|
||||
|
||||
.line 59
|
||||
invoke-interface {p0}, Landroid/content/SharedPreferences$Editor;->apply()V
|
||||
|
||||
const-string p0, "CommunityServerManager"
|
||||
|
||||
const-string v0, "\u274c Server URL cleared"
|
||||
|
||||
.line 61
|
||||
invoke-static {p0, v0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public static getServerUrl(Landroid/content/Context;)Ljava/lang/String;
|
||||
.locals 3
|
||||
|
||||
const-string v0, "rr3_community_server"
|
||||
|
||||
const/4 v1, 0x0
|
||||
|
||||
.line 28
|
||||
invoke-virtual {p0, v0, v1}, Landroid/content/Context;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;
|
||||
|
||||
move-result-object p0
|
||||
|
||||
const-string v0, "server_url"
|
||||
|
||||
const-string v1, ""
|
||||
|
||||
.line 29
|
||||
invoke-interface {p0, v0, v1}, Landroid/content/SharedPreferences;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
|
||||
|
||||
move-result-object p0
|
||||
|
||||
.line 31
|
||||
new-instance v0, Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
|
||||
|
||||
const-string v1, "\ud83d\udd17 Getting server URL: "
|
||||
|
||||
invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-virtual {v0, p0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
const-string v1, "CommunityServerManager"
|
||||
|
||||
invoke-static {v1, v0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
|
||||
|
||||
return-object p0
|
||||
.end method
|
||||
|
||||
.method public static saveServerUrl(Landroid/content/Context;Ljava/lang/String;)V
|
||||
.locals 2
|
||||
|
||||
const-string v0, "rr3_community_server"
|
||||
|
||||
const/4 v1, 0x0
|
||||
|
||||
.line 41
|
||||
invoke-virtual {p0, v0, v1}, Landroid/content/Context;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;
|
||||
|
||||
move-result-object p0
|
||||
|
||||
.line 42
|
||||
invoke-interface {p0}, Landroid/content/SharedPreferences;->edit()Landroid/content/SharedPreferences$Editor;
|
||||
|
||||
move-result-object p0
|
||||
|
||||
const-string v0, "server_url"
|
||||
|
||||
.line 43
|
||||
invoke-interface {p0, v0, p1}, Landroid/content/SharedPreferences$Editor;->putString(Ljava/lang/String;Ljava/lang/String;)Landroid/content/SharedPreferences$Editor;
|
||||
|
||||
.line 44
|
||||
invoke-interface {p0}, Landroid/content/SharedPreferences$Editor;->apply()V
|
||||
|
||||
.line 46
|
||||
new-instance p0, Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-direct {p0}, Ljava/lang/StringBuilder;-><init>()V
|
||||
|
||||
const-string v0, "\u2705 Server URL saved: "
|
||||
|
||||
invoke-virtual {p0, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-virtual {p0, p1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-virtual {p0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
|
||||
|
||||
move-result-object p0
|
||||
|
||||
const-string p1, "CommunityServerManager"
|
||||
|
||||
invoke-static {p1, p0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
|
||||
|
||||
return-void
|
||||
.end method
|
||||
@@ -2014,6 +2014,41 @@
|
||||
.line 1418
|
||||
invoke-super {p0, p1, p2, p3}, Lcom/firemonkeys/cloudcellapi/CC_Activity;->onActivityResult(IILandroid/content/Intent;)V
|
||||
|
||||
# 🆕 COMMUNITY PATCH: Handle ServerSetupActivity result
|
||||
const/16 v0, 0x1001
|
||||
|
||||
if-ne p1, v0, :check_wifi
|
||||
|
||||
# ServerSetupActivity returned
|
||||
const/4 v0, -0x1
|
||||
|
||||
if-ne p2, v0, :setup_cancelled
|
||||
|
||||
# RESULT_OK - Server URL was configured, continue boot
|
||||
const-string v0, "✅ Server configured - continuing boot"
|
||||
|
||||
const-string v1, "MainActivity"
|
||||
|
||||
invoke-static {v1, v0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
|
||||
|
||||
# Restart activity to continue normal boot sequence
|
||||
invoke-virtual {p0}, Landroid/app/Activity;->recreate()V
|
||||
|
||||
return-void
|
||||
|
||||
:setup_cancelled
|
||||
# User cancelled setup - exit app
|
||||
const-string v0, "❌ Server setup cancelled - exiting"
|
||||
|
||||
const-string v1, "MainActivity"
|
||||
|
||||
invoke-static {v1, v0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
|
||||
|
||||
invoke-virtual {p0}, Landroid/app/Activity;->finish()V
|
||||
|
||||
return-void
|
||||
|
||||
:check_wifi
|
||||
const v0, 0x13a286e3
|
||||
|
||||
const/4 v1, 0x0
|
||||
@@ -2306,6 +2341,41 @@
|
||||
.line 362
|
||||
invoke-super {p0, p1}, Lcom/firemonkeys/cloudcellapi/CC_Activity;->onCreate(Landroid/os/Bundle;)V
|
||||
|
||||
# 🆕 COMMUNITY PATCH: Check for server URL before continuing boot
|
||||
.line 363
|
||||
invoke-static {p0}, Lcom/firemint/realracing/CommunityServerManager;->checkServerUrl(Landroid/content/Context;)Z
|
||||
|
||||
move-result v0
|
||||
|
||||
if-nez v0, :server_configured
|
||||
|
||||
# No server URL configured - show setup dialog
|
||||
const-string v0, "⚠️ No server URL configured - showing setup dialog"
|
||||
|
||||
const-string v1, "MainActivity"
|
||||
|
||||
invoke-static {v1, v0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
|
||||
|
||||
new-instance v0, Landroid/content/Intent;
|
||||
|
||||
const-class v1, Lcom/firemint/realracing/ServerSetupActivity;
|
||||
|
||||
invoke-direct {v0, p0, v1}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V
|
||||
|
||||
const/16 v1, 0x1001
|
||||
|
||||
invoke-virtual {p0, v0, v1}, Landroid/app/Activity;->startActivityForResult(Landroid/content/Intent;I)V
|
||||
|
||||
# Don't continue boot - wait for setup to complete
|
||||
return-void
|
||||
|
||||
:server_configured
|
||||
const-string v0, "✅ Server URL configured - continuing boot"
|
||||
|
||||
const-string v1, "MainActivity"
|
||||
|
||||
invoke-static {v1, v0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
|
||||
|
||||
.line 365
|
||||
new-instance v0, Lcom/firemint/realracing/NotificationChannelHelper;
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
.class Lcom/firemint/realracing/ServerSetupActivity$1;
|
||||
.super Ljava/lang/Object;
|
||||
.source "ServerSetupActivity.java"
|
||||
|
||||
# interfaces
|
||||
.implements Landroid/view/View$OnClickListener;
|
||||
|
||||
|
||||
# annotations
|
||||
.annotation system Ldalvik/annotation/EnclosingMethod;
|
||||
value = Lcom/firemint/realracing/ServerSetupActivity;->onCreate(Landroid/os/Bundle;)V
|
||||
.end annotation
|
||||
|
||||
.annotation system Ldalvik/annotation/InnerClass;
|
||||
accessFlags = 0x0
|
||||
name = null
|
||||
.end annotation
|
||||
|
||||
|
||||
# instance fields
|
||||
.field final synthetic this$0:Lcom/firemint/realracing/ServerSetupActivity;
|
||||
|
||||
|
||||
# direct methods
|
||||
.method constructor <init>(Lcom/firemint/realracing/ServerSetupActivity;)V
|
||||
.locals 0
|
||||
|
||||
.line 47
|
||||
iput-object p1, p0, Lcom/firemint/realracing/ServerSetupActivity$1;->this$0:Lcom/firemint/realracing/ServerSetupActivity;
|
||||
|
||||
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
|
||||
# virtual methods
|
||||
.method public onClick(Landroid/view/View;)V
|
||||
.locals 0
|
||||
|
||||
.line 50
|
||||
iget-object p1, p0, Lcom/firemint/realracing/ServerSetupActivity$1;->this$0:Lcom/firemint/realracing/ServerSetupActivity;
|
||||
|
||||
invoke-static {p1}, Lcom/firemint/realracing/ServerSetupActivity;->access$000(Lcom/firemint/realracing/ServerSetupActivity;)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
@@ -0,0 +1,107 @@
|
||||
.class Lcom/firemint/realracing/ServerSetupActivity$2$1;
|
||||
.super Ljava/lang/Object;
|
||||
.source "ServerSetupActivity.java"
|
||||
|
||||
# interfaces
|
||||
.implements Ljava/lang/Runnable;
|
||||
|
||||
|
||||
# annotations
|
||||
.annotation system Ldalvik/annotation/EnclosingMethod;
|
||||
value = Lcom/firemint/realracing/ServerSetupActivity$2;->run()V
|
||||
.end annotation
|
||||
|
||||
.annotation system Ldalvik/annotation/InnerClass;
|
||||
accessFlags = 0x0
|
||||
name = null
|
||||
.end annotation
|
||||
|
||||
|
||||
# instance fields
|
||||
.field final synthetic this$1:Lcom/firemint/realracing/ServerSetupActivity$2;
|
||||
|
||||
.field final synthetic val$success:Z
|
||||
|
||||
|
||||
# direct methods
|
||||
.method constructor <init>(Lcom/firemint/realracing/ServerSetupActivity$2;Z)V
|
||||
.locals 0
|
||||
|
||||
.line 147
|
||||
iput-object p1, p0, Lcom/firemint/realracing/ServerSetupActivity$2$1;->this$1:Lcom/firemint/realracing/ServerSetupActivity$2;
|
||||
|
||||
iput-boolean p2, p0, Lcom/firemint/realracing/ServerSetupActivity$2$1;->val$success:Z
|
||||
|
||||
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
|
||||
# virtual methods
|
||||
.method public run()V
|
||||
.locals 2
|
||||
|
||||
.line 150
|
||||
iget-boolean v0, p0, Lcom/firemint/realracing/ServerSetupActivity$2$1;->val$success:Z
|
||||
|
||||
if-eqz v0, :cond_0
|
||||
|
||||
.line 151
|
||||
iget-object v0, p0, Lcom/firemint/realracing/ServerSetupActivity$2$1;->this$1:Lcom/firemint/realracing/ServerSetupActivity$2;
|
||||
|
||||
iget-object v0, v0, Lcom/firemint/realracing/ServerSetupActivity$2;->this$0:Lcom/firemint/realracing/ServerSetupActivity;
|
||||
|
||||
invoke-static {v0}, Lcom/firemint/realracing/ServerSetupActivity;->access$200(Lcom/firemint/realracing/ServerSetupActivity;)Landroid/widget/TextView;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
const-string v1, "\u2705 Connection successful!"
|
||||
|
||||
invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
|
||||
|
||||
.line 152
|
||||
iget-object v0, p0, Lcom/firemint/realracing/ServerSetupActivity$2$1;->this$1:Lcom/firemint/realracing/ServerSetupActivity$2;
|
||||
|
||||
iget-object v0, v0, Lcom/firemint/realracing/ServerSetupActivity$2;->this$0:Lcom/firemint/realracing/ServerSetupActivity;
|
||||
|
||||
invoke-static {v0}, Lcom/firemint/realracing/ServerSetupActivity;->access$200(Lcom/firemint/realracing/ServerSetupActivity;)Landroid/widget/TextView;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
const v1, -0xff6634
|
||||
|
||||
invoke-virtual {v0, v1}, Landroid/widget/TextView;->setTextColor(I)V
|
||||
|
||||
goto :goto_0
|
||||
|
||||
.line 154
|
||||
:cond_0
|
||||
iget-object v0, p0, Lcom/firemint/realracing/ServerSetupActivity$2$1;->this$1:Lcom/firemint/realracing/ServerSetupActivity$2;
|
||||
|
||||
iget-object v0, v0, Lcom/firemint/realracing/ServerSetupActivity$2;->this$0:Lcom/firemint/realracing/ServerSetupActivity;
|
||||
|
||||
invoke-static {v0}, Lcom/firemint/realracing/ServerSetupActivity;->access$200(Lcom/firemint/realracing/ServerSetupActivity;)Landroid/widget/TextView;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
const-string v1, "\u274c Could not connect to server"
|
||||
|
||||
invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
|
||||
|
||||
.line 155
|
||||
iget-object v0, p0, Lcom/firemint/realracing/ServerSetupActivity$2$1;->this$1:Lcom/firemint/realracing/ServerSetupActivity$2;
|
||||
|
||||
iget-object v0, v0, Lcom/firemint/realracing/ServerSetupActivity$2;->this$0:Lcom/firemint/realracing/ServerSetupActivity;
|
||||
|
||||
invoke-static {v0}, Lcom/firemint/realracing/ServerSetupActivity;->access$200(Lcom/firemint/realracing/ServerSetupActivity;)Landroid/widget/TextView;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
const/high16 v1, -0x10000
|
||||
|
||||
invoke-virtual {v0, v1}, Landroid/widget/TextView;->setTextColor(I)V
|
||||
|
||||
:goto_0
|
||||
return-void
|
||||
.end method
|
||||
@@ -0,0 +1,233 @@
|
||||
.class Lcom/firemint/realracing/ServerSetupActivity$2;
|
||||
.super Ljava/lang/Thread;
|
||||
.source "ServerSetupActivity.java"
|
||||
|
||||
|
||||
# annotations
|
||||
.annotation system Ldalvik/annotation/EnclosingMethod;
|
||||
value = Lcom/firemint/realracing/ServerSetupActivity;->testConnection()V
|
||||
.end annotation
|
||||
|
||||
.annotation system Ldalvik/annotation/InnerClass;
|
||||
accessFlags = 0x0
|
||||
name = null
|
||||
.end annotation
|
||||
|
||||
|
||||
# instance fields
|
||||
.field final synthetic this$0:Lcom/firemint/realracing/ServerSetupActivity;
|
||||
|
||||
.field final synthetic val$serverUrl:Ljava/lang/String;
|
||||
|
||||
|
||||
# direct methods
|
||||
.method constructor <init>(Lcom/firemint/realracing/ServerSetupActivity;Ljava/lang/String;)V
|
||||
.locals 0
|
||||
|
||||
.line 132
|
||||
iput-object p1, p0, Lcom/firemint/realracing/ServerSetupActivity$2;->this$0:Lcom/firemint/realracing/ServerSetupActivity;
|
||||
|
||||
iput-object p2, p0, Lcom/firemint/realracing/ServerSetupActivity$2;->val$serverUrl:Ljava/lang/String;
|
||||
|
||||
invoke-direct {p0}, Ljava/lang/Thread;-><init>()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
|
||||
# virtual methods
|
||||
.method public run()V
|
||||
.locals 6
|
||||
|
||||
const-string v0, "ServerSetupActivity"
|
||||
|
||||
const/4 v1, 0x0
|
||||
|
||||
.line 137
|
||||
:try_start_0
|
||||
new-instance v2, Ljava/net/URL;
|
||||
|
||||
new-instance v3, Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V
|
||||
|
||||
iget-object v4, p0, Lcom/firemint/realracing/ServerSetupActivity$2;->val$serverUrl:Ljava/lang/String;
|
||||
|
||||
invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
||||
|
||||
const-string v4, "/director/api/android/getDirectionByPackage"
|
||||
|
||||
invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
|
||||
|
||||
move-result-object v3
|
||||
|
||||
invoke-direct {v2, v3}, Ljava/net/URL;-><init>(Ljava/lang/String;)V
|
||||
|
||||
.line 138
|
||||
invoke-virtual {v2}, Ljava/net/URL;->openConnection()Ljava/net/URLConnection;
|
||||
|
||||
move-result-object v2
|
||||
|
||||
check-cast v2, Ljava/net/HttpURLConnection;
|
||||
:try_end_0
|
||||
.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_1
|
||||
.catchall {:try_start_0 .. :try_end_0} :catchall_1
|
||||
|
||||
const/16 v1, 0x1388
|
||||
|
||||
.line 139
|
||||
:try_start_1
|
||||
invoke-virtual {v2, v1}, Ljava/net/HttpURLConnection;->setConnectTimeout(I)V
|
||||
|
||||
.line 140
|
||||
invoke-virtual {v2, v1}, Ljava/net/HttpURLConnection;->setReadTimeout(I)V
|
||||
|
||||
.line 141
|
||||
invoke-virtual {v2}, Ljava/net/HttpURLConnection;->connect()V
|
||||
|
||||
.line 143
|
||||
invoke-virtual {v2}, Ljava/net/HttpURLConnection;->getResponseCode()I
|
||||
|
||||
move-result v1
|
||||
|
||||
.line 144
|
||||
new-instance v3, Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V
|
||||
|
||||
const-string v4, "\ud83d\udd0d Test connection response code: "
|
||||
|
||||
invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-virtual {v3, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
|
||||
|
||||
move-result-object v3
|
||||
|
||||
invoke-static {v0, v3}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
|
||||
|
||||
const/16 v3, 0xc8
|
||||
|
||||
if-ne v1, v3, :cond_0
|
||||
|
||||
const/4 v1, 0x1
|
||||
|
||||
goto :goto_0
|
||||
|
||||
:cond_0
|
||||
const/4 v1, 0x0
|
||||
|
||||
.line 147
|
||||
:goto_0
|
||||
iget-object v3, p0, Lcom/firemint/realracing/ServerSetupActivity$2;->this$0:Lcom/firemint/realracing/ServerSetupActivity;
|
||||
|
||||
new-instance v4, Lcom/firemint/realracing/ServerSetupActivity$2$1;
|
||||
|
||||
invoke-direct {v4, p0, v1}, Lcom/firemint/realracing/ServerSetupActivity$2$1;-><init>(Lcom/firemint/realracing/ServerSetupActivity$2;Z)V
|
||||
|
||||
invoke-virtual {v3, v4}, Landroid/app/Activity;->runOnUiThread(Ljava/lang/Runnable;)V
|
||||
:try_end_1
|
||||
.catch Ljava/lang/Exception; {:try_start_1 .. :try_end_1} :catch_0
|
||||
.catchall {:try_start_1 .. :try_end_1} :catchall_0
|
||||
|
||||
if-eqz v2, :cond_2
|
||||
|
||||
.line 162
|
||||
invoke-virtual {v2}, Ljava/net/HttpURLConnection;->disconnect()V
|
||||
|
||||
goto :goto_3
|
||||
|
||||
:catchall_0
|
||||
move-exception v0
|
||||
|
||||
move-object v1, v2
|
||||
|
||||
goto :goto_4
|
||||
|
||||
:catch_0
|
||||
move-exception v1
|
||||
|
||||
move-object v5, v2
|
||||
|
||||
move-object v2, v1
|
||||
|
||||
move-object v1, v5
|
||||
|
||||
goto :goto_1
|
||||
|
||||
:catchall_1
|
||||
move-exception v0
|
||||
|
||||
goto :goto_4
|
||||
|
||||
:catch_1
|
||||
move-exception v2
|
||||
|
||||
.line 157
|
||||
:goto_1
|
||||
:try_start_2
|
||||
new-instance v3, Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V
|
||||
|
||||
const-string v4, "\u274c Test connection failed: "
|
||||
|
||||
invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-virtual {v2}, Ljava/lang/Exception;->getMessage()Ljava/lang/String;
|
||||
|
||||
move-result-object v2
|
||||
|
||||
invoke-virtual {v3, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
|
||||
|
||||
move-result-object v2
|
||||
|
||||
invoke-static {v0, v2}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
|
||||
|
||||
.line 158
|
||||
iget-object v0, p0, Lcom/firemint/realracing/ServerSetupActivity$2;->this$0:Lcom/firemint/realracing/ServerSetupActivity;
|
||||
|
||||
new-instance v2, Lcom/firemint/realracing/ServerSetupActivity$2$1;
|
||||
|
||||
const/4 v3, 0x0
|
||||
|
||||
invoke-direct {v2, p0, v3}, Lcom/firemint/realracing/ServerSetupActivity$2$1;-><init>(Lcom/firemint/realracing/ServerSetupActivity$2;Z)V
|
||||
|
||||
invoke-virtual {v0, v2}, Landroid/app/Activity;->runOnUiThread(Ljava/lang/Runnable;)V
|
||||
:try_end_2
|
||||
.catchall {:try_start_2 .. :try_end_2} :catchall_1
|
||||
|
||||
if-eqz v1, :cond_2
|
||||
|
||||
.line 162
|
||||
check-cast v1, Ljava/net/HttpURLConnection;
|
||||
|
||||
invoke-virtual {v1}, Ljava/net/HttpURLConnection;->disconnect()V
|
||||
|
||||
goto :goto_3
|
||||
|
||||
:goto_2
|
||||
if-eqz v1, :cond_1
|
||||
|
||||
check-cast v1, Ljava/net/HttpURLConnection;
|
||||
|
||||
invoke-virtual {v1}, Ljava/net/HttpURLConnection;->disconnect()V
|
||||
|
||||
.line 165
|
||||
:cond_1
|
||||
throw v0
|
||||
|
||||
:cond_2
|
||||
:goto_3
|
||||
return-void
|
||||
|
||||
:goto_4
|
||||
move-object v1, v5
|
||||
|
||||
goto :goto_2
|
||||
.end method
|
||||
@@ -0,0 +1,47 @@
|
||||
.class Lcom/firemint/realracing/ServerSetupActivity$3;
|
||||
.super Ljava/lang/Object;
|
||||
.source "ServerSetupActivity.java"
|
||||
|
||||
# interfaces
|
||||
.implements Landroid/view/View$OnClickListener;
|
||||
|
||||
|
||||
# annotations
|
||||
.annotation system Ldalvik/annotation/EnclosingMethod;
|
||||
value = Lcom/firemint/realracing/ServerSetupActivity;->onCreate(Landroid/os/Bundle;)V
|
||||
.end annotation
|
||||
|
||||
.annotation system Ldalvik/annotation/InnerClass;
|
||||
accessFlags = 0x0
|
||||
name = null
|
||||
.end annotation
|
||||
|
||||
|
||||
# instance fields
|
||||
.field final synthetic this$0:Lcom/firemint/realracing/ServerSetupActivity;
|
||||
|
||||
|
||||
# direct methods
|
||||
.method constructor <init>(Lcom/firemint/realracing/ServerSetupActivity;)V
|
||||
.locals 0
|
||||
|
||||
.line 55
|
||||
iput-object p1, p0, Lcom/firemint/realracing/ServerSetupActivity$3;->this$0:Lcom/firemint/realracing/ServerSetupActivity;
|
||||
|
||||
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
|
||||
# virtual methods
|
||||
.method public onClick(Landroid/view/View;)V
|
||||
.locals 0
|
||||
|
||||
.line 58
|
||||
iget-object p1, p0, Lcom/firemint/realracing/ServerSetupActivity$3;->this$0:Lcom/firemint/realracing/ServerSetupActivity;
|
||||
|
||||
invoke-static {p1}, Lcom/firemint/realracing/ServerSetupActivity;->access$100(Lcom/firemint/realracing/ServerSetupActivity;)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
357
smali_classes2/com/firemint/realracing/ServerSetupActivity.smali
Normal file
357
smali_classes2/com/firemint/realracing/ServerSetupActivity.smali
Normal file
@@ -0,0 +1,357 @@
|
||||
.class public Lcom/firemint/realracing/ServerSetupActivity;
|
||||
.super Landroid/app/Activity;
|
||||
.source "ServerSetupActivity.java"
|
||||
|
||||
|
||||
# static fields
|
||||
.field private static final TAG:Ljava/lang/String; = "ServerSetupActivity"
|
||||
|
||||
|
||||
# instance fields
|
||||
.field private buttonContinue:Landroid/widget/Button;
|
||||
|
||||
.field private buttonTest:Landroid/widget/Button;
|
||||
|
||||
.field private editTextServerUrl:Landroid/widget/EditText;
|
||||
|
||||
.field private textViewStatus:Landroid/widget/TextView;
|
||||
|
||||
|
||||
# direct methods
|
||||
.method public constructor <init>()V
|
||||
.locals 0
|
||||
|
||||
.line 15
|
||||
invoke-direct {p0}, Landroid/app/Activity;-><init>()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method static synthetic access$000(Lcom/firemint/realracing/ServerSetupActivity;)V
|
||||
.locals 0
|
||||
|
||||
.line 15
|
||||
invoke-direct {p0}, Lcom/firemint/realracing/ServerSetupActivity;->testConnection()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method static synthetic access$100(Lcom/firemint/realracing/ServerSetupActivity;)V
|
||||
.locals 0
|
||||
|
||||
.line 15
|
||||
invoke-direct {p0}, Lcom/firemint/realracing/ServerSetupActivity;->continueToGame()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method static synthetic access$200(Lcom/firemint/realracing/ServerSetupActivity;)Landroid/widget/TextView;
|
||||
.locals 0
|
||||
|
||||
.line 15
|
||||
iget-object p0, p0, Lcom/firemint/realracing/ServerSetupActivity;->textViewStatus:Landroid/widget/TextView;
|
||||
|
||||
return-object p0
|
||||
.end method
|
||||
|
||||
.method private continueToGame()V
|
||||
.locals 4
|
||||
|
||||
.line 78
|
||||
iget-object v0, p0, Lcom/firemint/realracing/ServerSetupActivity;->editTextServerUrl:Landroid/widget/EditText;
|
||||
|
||||
invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
invoke-virtual {v0}, Ljava/lang/String;->trim()Ljava/lang/String;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
.line 81
|
||||
invoke-direct {p0, v0}, Lcom/firemint/realracing/ServerSetupActivity;->isValidUrl(Ljava/lang/String;)Z
|
||||
|
||||
move-result v1
|
||||
|
||||
if-nez v1, :cond_0
|
||||
|
||||
.line 82
|
||||
iget-object v0, p0, Lcom/firemint/realracing/ServerSetupActivity;->textViewStatus:Landroid/widget/TextView;
|
||||
|
||||
const-string v1, "\u274c Invalid URL format. Example: https://rr3.example.com:5001"
|
||||
|
||||
invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
|
||||
|
||||
.line 83
|
||||
iget-object v0, p0, Lcom/firemint/realracing/ServerSetupActivity;->textViewStatus:Landroid/widget/TextView;
|
||||
|
||||
const/4 v1, 0x0
|
||||
|
||||
invoke-virtual {v0, v1}, Landroid/widget/TextView;->setVisibility(I)V
|
||||
|
||||
return-void
|
||||
|
||||
.line 88
|
||||
:cond_0
|
||||
invoke-static {p0, v0}, Lcom/firemint/realracing/CommunityServerManager;->saveServerUrl(Landroid/content/Context;Ljava/lang/String;)V
|
||||
|
||||
.line 91
|
||||
new-instance v1, Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
|
||||
|
||||
const-string v2, "\u2705 Server URL configured: "
|
||||
|
||||
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
const-string v1, "ServerSetupActivity"
|
||||
|
||||
invoke-static {v1, v0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
|
||||
|
||||
.line 94
|
||||
new-instance v0, Landroid/content/Intent;
|
||||
|
||||
invoke-direct {v0}, Landroid/content/Intent;-><init>()V
|
||||
|
||||
const/4 v1, -0x1
|
||||
|
||||
.line 95
|
||||
invoke-virtual {p0, v1, v0}, Lcom/firemint/realracing/ServerSetupActivity;->setResult(ILandroid/content/Intent;)V
|
||||
|
||||
.line 96
|
||||
invoke-virtual {p0}, Lcom/firemint/realracing/ServerSetupActivity;->finish()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method private isValidUrl(Ljava/lang/String;)Z
|
||||
.locals 1
|
||||
|
||||
if-eqz p1, :cond_2
|
||||
|
||||
.line 103
|
||||
invoke-virtual {p1}, Ljava/lang/String;->isEmpty()Z
|
||||
|
||||
move-result v0
|
||||
|
||||
if-eqz v0, :cond_0
|
||||
|
||||
goto :cond_2
|
||||
|
||||
:cond_0
|
||||
const-string v0, "http://"
|
||||
|
||||
.line 107
|
||||
invoke-virtual {p1, v0}, Ljava/lang/String;->startsWith(Ljava/lang/String;)Z
|
||||
|
||||
move-result v0
|
||||
|
||||
if-nez v0, :cond_1
|
||||
|
||||
const-string v0, "https://"
|
||||
|
||||
invoke-virtual {p1, v0}, Ljava/lang/String;->startsWith(Ljava/lang/String;)Z
|
||||
|
||||
move-result p1
|
||||
|
||||
if-eqz p1, :cond_2
|
||||
|
||||
:cond_1
|
||||
const/4 p1, 0x1
|
||||
|
||||
return p1
|
||||
|
||||
:cond_2
|
||||
const/4 p1, 0x0
|
||||
|
||||
return p1
|
||||
.end method
|
||||
|
||||
.method private testConnection()V
|
||||
.locals 4
|
||||
|
||||
.line 117
|
||||
iget-object v0, p0, Lcom/firemint/realracing/ServerSetupActivity;->editTextServerUrl:Landroid/widget/EditText;
|
||||
|
||||
invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
invoke-virtual {v0}, Ljava/lang/String;->trim()Ljava/lang/String;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
.line 120
|
||||
invoke-direct {p0, v0}, Lcom/firemint/realracing/ServerSetupActivity;->isValidUrl(Ljava/lang/String;)Z
|
||||
|
||||
move-result v1
|
||||
|
||||
if-nez v1, :cond_0
|
||||
|
||||
.line 121
|
||||
iget-object v0, p0, Lcom/firemint/realracing/ServerSetupActivity;->textViewStatus:Landroid/widget/TextView;
|
||||
|
||||
const-string v1, "\u274c Invalid URL format"
|
||||
|
||||
invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
|
||||
|
||||
.line 122
|
||||
iget-object v0, p0, Lcom/firemint/realracing/ServerSetupActivity;->textViewStatus:Landroid/widget/TextView;
|
||||
|
||||
const/4 v1, 0x0
|
||||
|
||||
invoke-virtual {v0, v1}, Landroid/widget/TextView;->setVisibility(I)V
|
||||
|
||||
return-void
|
||||
|
||||
.line 127
|
||||
:cond_0
|
||||
iget-object v1, p0, Lcom/firemint/realracing/ServerSetupActivity;->textViewStatus:Landroid/widget/TextView;
|
||||
|
||||
const-string v2, "\ud83d\udd0d Testing connection..."
|
||||
|
||||
invoke-virtual {v1, v2}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
|
||||
|
||||
.line 128
|
||||
iget-object v1, p0, Lcom/firemint/realracing/ServerSetupActivity;->textViewStatus:Landroid/widget/TextView;
|
||||
|
||||
const/high16 v2, -0x1000000
|
||||
|
||||
invoke-virtual {v1, v2}, Landroid/widget/TextView;->setTextColor(I)V
|
||||
|
||||
.line 129
|
||||
iget-object v1, p0, Lcom/firemint/realracing/ServerSetupActivity;->textViewStatus:Landroid/widget/TextView;
|
||||
|
||||
const/4 v2, 0x0
|
||||
|
||||
invoke-virtual {v1, v2}, Landroid/widget/TextView;->setVisibility(I)V
|
||||
|
||||
.line 132
|
||||
new-instance v1, Lcom/firemint/realracing/ServerSetupActivity$2;
|
||||
|
||||
invoke-direct {v1, p0, v0}, Lcom/firemint/realracing/ServerSetupActivity$2;-><init>(Lcom/firemint/realracing/ServerSetupActivity;Ljava/lang/String;)V
|
||||
|
||||
.line 168
|
||||
invoke-virtual {v1}, Ljava/lang/Thread;->start()V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
|
||||
# virtual methods
|
||||
.method protected onCreate(Landroid/os/Bundle;)V
|
||||
.locals 2
|
||||
|
||||
.line 29
|
||||
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
|
||||
|
||||
const p1, 0x7f0b001c
|
||||
|
||||
.line 30
|
||||
invoke-virtual {p0, p1}, Lcom/firemint/realracing/ServerSetupActivity;->setContentView(I)V
|
||||
|
||||
const-string p1, "ServerSetupActivity"
|
||||
|
||||
const-string v0, "\ud83d\udd27 Server Setup Activity started"
|
||||
|
||||
.line 32
|
||||
invoke-static {p1, v0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
|
||||
|
||||
const p1, 0x7f080113
|
||||
|
||||
.line 35
|
||||
invoke-virtual {p0, p1}, Lcom/firemint/realracing/ServerSetupActivity;->findViewById(I)Landroid/view/View;
|
||||
|
||||
move-result-object p1
|
||||
|
||||
check-cast p1, Landroid/widget/EditText;
|
||||
|
||||
iput-object p1, p0, Lcom/firemint/realracing/ServerSetupActivity;->editTextServerUrl:Landroid/widget/EditText;
|
||||
|
||||
const p1, 0x7f0800f8
|
||||
|
||||
.line 36
|
||||
invoke-virtual {p0, p1}, Lcom/firemint/realracing/ServerSetupActivity;->findViewById(I)Landroid/view/View;
|
||||
|
||||
move-result-object p1
|
||||
|
||||
check-cast p1, Landroid/widget/Button;
|
||||
|
||||
iput-object p1, p0, Lcom/firemint/realracing/ServerSetupActivity;->buttonTest:Landroid/widget/Button;
|
||||
|
||||
const p1, 0x7f0800f7
|
||||
|
||||
.line 37
|
||||
invoke-virtual {p0, p1}, Lcom/firemint/realracing/ServerSetupActivity;->findViewById(I)Landroid/view/View;
|
||||
|
||||
move-result-object p1
|
||||
|
||||
check-cast p1, Landroid/widget/Button;
|
||||
|
||||
iput-object p1, p0, Lcom/firemint/realracing/ServerSetupActivity;->buttonContinue:Landroid/widget/Button;
|
||||
|
||||
const p1, 0x7f0802e5
|
||||
|
||||
.line 38
|
||||
invoke-virtual {p0, p1}, Lcom/firemint/realracing/ServerSetupActivity;->findViewById(I)Landroid/view/View;
|
||||
|
||||
move-result-object p1
|
||||
|
||||
check-cast p1, Landroid/widget/TextView;
|
||||
|
||||
iput-object p1, p0, Lcom/firemint/realracing/ServerSetupActivity;->textViewStatus:Landroid/widget/TextView;
|
||||
|
||||
.line 41
|
||||
invoke-static {p0}, Lcom/firemint/realracing/CommunityServerManager;->getServerUrl(Landroid/content/Context;)Ljava/lang/String;
|
||||
|
||||
move-result-object p1
|
||||
|
||||
if-eqz p1, :cond_0
|
||||
|
||||
.line 42
|
||||
invoke-virtual {p1}, Ljava/lang/String;->isEmpty()Z
|
||||
|
||||
move-result v0
|
||||
|
||||
if-nez v0, :cond_0
|
||||
|
||||
.line 43
|
||||
iget-object v0, p0, Lcom/firemint/realracing/ServerSetupActivity;->editTextServerUrl:Landroid/widget/EditText;
|
||||
|
||||
invoke-virtual {v0, p1}, Landroid/widget/EditText;->setText(Ljava/lang/CharSequence;)V
|
||||
|
||||
.line 47
|
||||
:cond_0
|
||||
iget-object p1, p0, Lcom/firemint/realracing/ServerSetupActivity;->buttonTest:Landroid/widget/Button;
|
||||
|
||||
new-instance v0, Lcom/firemint/realracing/ServerSetupActivity$1;
|
||||
|
||||
invoke-direct {v0, p0}, Lcom/firemint/realracing/ServerSetupActivity$1;-><init>(Lcom/firemint/realracing/ServerSetupActivity;)V
|
||||
|
||||
invoke-virtual {p1, v0}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
|
||||
|
||||
.line 55
|
||||
iget-object p1, p0, Lcom/firemint/realracing/ServerSetupActivity;->buttonContinue:Landroid/widget/Button;
|
||||
|
||||
new-instance v0, Lcom/firemint/realracing/ServerSetupActivity$3;
|
||||
|
||||
invoke-direct {v0, p0}, Lcom/firemint/realracing/ServerSetupActivity$3;-><init>(Lcom/firemint/realracing/ServerSetupActivity;)V
|
||||
|
||||
invoke-virtual {p1, v0}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
Reference in New Issue
Block a user