Skip to content

Commit 3949927

Browse files
Merge branch 'stage' into ADFA-2124-Update-title-of-feedback-popup
2 parents af601c5 + 13be284 commit 3949927

File tree

39 files changed

+571
-797
lines changed

39 files changed

+571
-797
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
name: Generate Assets Zips and Upload to Google Drive
2+
3+
permissions:
4+
id-token: write
5+
contents: write
6+
actions: write
7+
8+
on:
9+
workflow_dispatch:
10+
11+
jobs:
12+
generate_assets:
13+
name: Generate Assets Zips
14+
runs-on: self-hosted
15+
timeout-minutes: 30
16+
17+
steps:
18+
- name: Checkout repository
19+
uses: actions/checkout@v4
20+
with:
21+
ref: stage
22+
23+
- name: Install Git LFS
24+
run: |
25+
sudo apt-get update
26+
sudo apt-get install -y git-lfs
27+
git lfs install
28+
git lfs pull
29+
30+
- name: Check if Nix is installed
31+
id: check_nix
32+
run: |
33+
if command -v nix >/dev/null 2>&1; then
34+
echo "nix is installed"
35+
echo "nix_installed=true" >> $GITHUB_ENV
36+
else
37+
echo "nix is not installed"
38+
echo "nix_installed=false" >> $GITHUB_ENV
39+
fi
40+
41+
- name: Install Flox
42+
if: env.nix_installed == 'false'
43+
uses: flox/install-flox-action@v2
44+
45+
- name: Create google-services.json
46+
env:
47+
GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }}
48+
run: |
49+
echo "$GOOGLE_SERVICES_JSON" > app/google-services.json
50+
echo "google-services.json created successfully"
51+
52+
- name: Authenticate to Google Cloud for Drive access
53+
id: auth_drive
54+
uses: google-github-actions/auth@v2
55+
with:
56+
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
57+
service_account: ${{ secrets.IDENTITY_EMAIL }}
58+
token_format: 'access_token'
59+
access_token_scopes: 'https://www.googleapis.com/auth/drive'
60+
61+
- name: Download latest documentation.db from Google Drive
62+
run: |
63+
DB_FILE_ID="${{ secrets.DOCUMENTATION_DB_FILE_ID }}"
64+
ACCESS_TOKEN="${{ steps.auth_drive.outputs.access_token }}"
65+
66+
if [ -z "DB_FILE_ID" ]; then
67+
echo "ERROR: DOCUMENTATION_DB_FILE_ID secret not set"
68+
echo "Please set the DOCUMENTATION_DB_FILE_ID secret in repository settings"
69+
exit 1
70+
fi
71+
72+
echo "Downloading documentation.db from Google Drive..."
73+
74+
mkdir -p assets
75+
curl -sL -H "Authorization: Bearer $ACCESS_TOKEN" \
76+
"https://www.googleapis.com/drive/v3/files/${DB_FILE_ID}?alt=media&supportsAllDrives=true&acknowledgeAbuse=true" \
77+
-o assets/documentation.db
78+
79+
if [ ! -f assets/documentation.db ]; then
80+
echo "ERROR: Failed to download documentation.db"
81+
exit 1
82+
fi
83+
84+
FILE_SIZE_BYTES=$(stat -c%s assets/documentation.db 2>/dev/null || stat -f%z assets/documentation.db 2>/dev/null)
85+
FILE_SIZE_HUMAN=$(du -h assets/documentation.db | cut -f1)
86+
87+
if [ "$FILE_SIZE_BYTES" -lt 1000000 ]; then
88+
echo "ERROR: Downloaded file is too small ($FILE_SIZE_HUMAN)"
89+
echo "This usually means the file was not found or service account lacks access"
90+
exit 1
91+
fi
92+
93+
echo "Successfully downloaded documentation.db ($FILE_SIZE_HUMAN)"
94+
95+
- name: Assemble Assets
96+
run: |
97+
flox activate -d flox/base -- ./gradlew :app:assembleAssets --no-daemon \
98+
-Dorg.gradle.jvmargs="-Xmx10g -XX:MaxMetaspaceSize=2g -XX:+HeapDumpOnOutOfMemoryError --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED" \
99+
-Dandroid.aapt2.daemonHeapSize=4096M \
100+
-Dorg.gradle.workers.max=1 \
101+
-Dorg.gradle.parallel=false
102+
103+
- name: V8 Assets Path
104+
id: assets_v8
105+
run: |
106+
assets_path="app/build/outputs/assets/assets-arm64-v8a.zip"
107+
echo "ASSETS_PATH=$assets_path" >> $GITHUB_OUTPUT
108+
109+
- name: V7 Assets Path
110+
id: assets_v7
111+
run: |
112+
assets_path="app/build/outputs/assets/assets-armeabi-v7a.zip"
113+
echo "ASSETS_PATH=$assets_path" >> $GITHUB_OUTPUT
114+
115+
- name: Upload asset zips to Google Drive
116+
run: |
117+
echo "Uploading assets v8 and v7 to Google Drive..."
118+
ls -la "${{ steps.assets_v8.outputs.ASSETS_PATH }}"
119+
ls -la "${{ steps.assets_v7.outputs.ASSETS_PATH }}"
120+
121+
ACCESS_TOKEN="${{ steps.auth_drive.outputs.access_token }}"
122+
V8_FILE_ID="${{ secrets.ASSETS_V8_FILE_ID }}"
123+
V7_FILE_ID="${{ secrets.ASSETS_V7_FILE_ID }}"
124+
125+
V8_PATH="${{ steps.assets_v8.outputs.ASSETS_PATH }}"
126+
V7_PATH="${{ steps.assets_v7.outputs.ASSETS_PATH }}"
127+
128+
# Upload v8
129+
response=$(curl -s -o /dev/null -w "%{http_code}" --fail -X PATCH \
130+
-H "Authorization: Bearer $ACCESS_TOKEN" \
131+
-F "file=@${V8_PATH};type=application/octet-stream" \
132+
"https://www.googleapis.com/upload/drive/v3/files/${V8_FILE_ID}?uploadType=media")
133+
134+
if [[ "$response" -ne 200 ]]; then
135+
echo "Upload of ${V8_PATH} failed with HTTP status $response"
136+
exit 1
137+
fi
138+
139+
# Upload v7
140+
response=$(curl -s -o /dev/null -w "%{http_code}" --fail -X PATCH \
141+
-H "Authorization: Bearer $ACCESS_TOKEN" \
142+
-F "file=@${V7_PATH};type=application/octet-stream" \
143+
"https://www.googleapis.com/upload/drive/v3/files/${V7_FILE_ID}?uploadType=media")
144+
145+
if [[ "$response" -ne 200 ]]; then
146+
echo "Upload of ${V7_PATH} failed with HTTP status $response"
147+
exit 1
148+
fi
149+
150+
echo "Upload complete."
151+
152+
- name: Send Rich Slack Notification
153+
env:
154+
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
155+
run: |
156+
V8_PATH="${{ steps.assets_v8.outputs.ASSETS_PATH }}"
157+
V7_PATH="${{ steps.assets_v7.outputs.ASSETS_PATH }}"
158+
159+
jq -n \
160+
--arg v8_path "$V8_PATH" \
161+
--arg v7_path "$V7_PATH" \
162+
'{
163+
blocks: [
164+
{
165+
type: "header",
166+
text: {
167+
type: "plain_text",
168+
text: ":rocket: [Updated] New Assets Zips Available",
169+
emoji: true
170+
}
171+
},
172+
{
173+
type: "section",
174+
text: {
175+
type: "mrkdwn",
176+
text: "*V8 Path:* `$v8_path`"
177+
}
178+
},
179+
{
180+
type: "section",
181+
text: {
182+
type: "mrkdwn",
183+
text: "*V7 Path:* `$v7_path`"
184+
}
185+
}
186+
]
187+
}' > payload.json
188+
189+
# curl -X POST -H "Content-type: application/json" --data @payload.json "$SLACK_WEBHOOK"
190+
191+
rm -f payload.json
192+
- name: Cleanup google-services.json
193+
if: always()
194+
run: |
195+
rm -f app/google-services.json
196+
echo "google-services.json cleaned up successfully"

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,7 @@ tests/test-home
128128
/sample-plugin/build/
129129
/keystore-generator-plugin/build/
130130
/keystore-generator-plugin/.kotlin/
131+
**/build
132+
133+
# Release files
134+
*.zim

app/build.gradle.kts

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import java.util.zip.Deflater
2121
import java.util.zip.ZipEntry
2222
import java.util.zip.ZipInputStream
2323
import java.util.zip.ZipOutputStream
24+
import java.util.zip.CRC32
2425
import kotlin.reflect.jvm.javaMethod
2526

2627
plugins {
@@ -400,11 +401,16 @@ tasks.register("recompressApk") {
400401
doLast {
401402
val abi: String = extensions.extraProperties["abi"].toString()
402403
val buildName: String = extensions.extraProperties["buildName"].toString()
404+
val noCompressExtensions = if (extensions.extraProperties.has("noCompressExtensions")) {
405+
extensions.extraProperties["noCompressExtensions"] as? Set<String> ?: emptySet()
406+
} else {
407+
emptySet()
408+
}
403409

404410
project.logger.lifecycle("Calling recompressApk abi:$abi buildName:$buildName")
405411

406412
val start = System.nanoTime()
407-
recompressApk(abi, buildName)
413+
recompressApk(abi, buildName, noCompressExtensions)
408414
val durationMs = "%.2f".format((System.nanoTime() - start) / 1_000_000.0)
409415

410416
project.logger.lifecycle("recompressApk completed in ${durationMs}ms")
@@ -413,6 +419,8 @@ tasks.register("recompressApk") {
413419

414420
val isCiCd = System.getenv("GITHUB_ACTIONS") == "true"
415421

422+
val noCompress = setOf("so", "ogg", "mp3", "mp4", "zip", "jar", "ttf", "otf", "br")
423+
416424
afterEvaluate {
417425
tasks.named("assembleV8Release").configure {
418426
finalizedBy("recompressApk")
@@ -421,22 +429,20 @@ afterEvaluate {
421429
tasks.named("recompressApk").configure {
422430
extensions.extraProperties["abi"] = "v8"
423431
extensions.extraProperties["buildName"] = "release"
432+
extensions.extraProperties["noCompressExtensions"] = noCompress
424433
}
425434
}
426435
}
427436

428437
tasks.named("assembleV7Release").configure {
429-
if (isCiCd) {
430-
finalizedBy("recompressApk")
431-
}
438+
finalizedBy("recompressApk")
432439

433440
doLast {
434-
if (isCiCd) {
435-
tasks.named("recompressApk").configure {
436-
extensions.extraProperties["abi"] = "v7"
437-
extensions.extraProperties["buildName"] = "release"
438-
}
439-
}
441+
tasks.named("recompressApk").configure {
442+
extensions.extraProperties["abi"] = "v7"
443+
extensions.extraProperties["buildName"] = "release"
444+
extensions.extraProperties["noCompressExtensions"] = noCompress
445+
}
440446
}
441447
}
442448

@@ -475,7 +481,10 @@ afterEvaluate {
475481
fun recompressApk(
476482
abi: String,
477483
buildName: String,
484+
noCompressExtensions: Set<String>
478485
) {
486+
project.logger.lifecycle("Recompressing APK with exclusions: $noCompressExtensions")
487+
479488
val apkDir: File =
480489
layout.buildDirectory
481490
.dir("outputs/apk/$abi/$buildName")
@@ -486,7 +495,7 @@ fun recompressApk(
486495
apkDir.walk().filter { it.extension == "apk" }.forEach { apkFile ->
487496
project.logger.lifecycle("Recompressing APK: ${apkFile.name}")
488497
val tempZipFile = File(apkFile.parentFile, "${apkFile.name}.tmp")
489-
recompressZip(apkFile, tempZipFile)
498+
recompressZip(apkFile, tempZipFile, noCompressExtensions)
490499
signApk(tempZipFile)
491500
if (apkFile.delete()) {
492501
tempZipFile.renameTo(apkFile)
@@ -497,6 +506,7 @@ fun recompressApk(
497506
fun recompressZip(
498507
inputZip: File,
499508
outputZip: File,
509+
noCompressExtensions: Set<String>
500510
) {
501511
ZipInputStream(BufferedInputStream(FileInputStream(inputZip))).use { zis ->
502512
ZipOutputStream(BufferedOutputStream(FileOutputStream(outputZip))).use { zos ->
@@ -505,6 +515,7 @@ fun recompressZip(
505515
var entry = zis.nextEntry
506516
while (entry != null) {
507517
if (!entry.isDirectory) {
518+
val extension = entry.name.substringAfterLast('.', "").lowercase()
508519
val newEntry = ZipEntry(entry.name)
509520

510521
// Remove timestamps for deterministic output (-X)
@@ -513,12 +524,22 @@ fun recompressZip(
513524
newEntry.creationTime = FileTime.fromMillis(0)
514525
newEntry.lastModifiedTime = FileTime.fromMillis(0)
515526
newEntry.lastAccessTime = FileTime.fromMillis(0)
516-
} catch (_: Throwable) {
517-
// In case JVM doesn't support them
527+
} catch (_: Throwable) {}
528+
529+
// Force STORE method for no-compress extensions
530+
if (extension in noCompressExtensions) {
531+
val byteArray = zis.readBytes()
532+
newEntry.method = ZipEntry.STORED
533+
newEntry.size = byteArray.size.toLong()
534+
newEntry.crc = CRC32().apply { update(byteArray) }.value
535+
zos.putNextEntry(newEntry)
536+
zos.write(byteArray)
537+
} else {
538+
newEntry.method = ZipEntry.DEFLATED
539+
zos.putNextEntry(newEntry)
540+
zis.copyTo(zos)
518541
}
519542

520-
zos.putNextEntry(newEntry)
521-
zis.copyTo(zos)
522543
zos.closeEntry()
523544
}
524545
entry = zis.nextEntry

app/src/main/AndroidManifest.xml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,11 @@
8989
android:name=".activities.MainActivity"
9090
android:exported="false"
9191
android:theme="@style/Theme.AndroidIDE" />
92-
<activity
93-
android:name=".activities.editor.EditorActivityKt"
94-
android:configChanges="orientation|screenSize"
95-
android:launchMode="singleTask" />
92+
<activity
93+
android:name=".activities.editor.EditorActivityKt"
94+
android:configChanges="orientation|screenSize"
95+
android:launchMode="singleTask"
96+
android:windowSoftInputMode="adjustResize" />
9697
<activity android:name=".activities.PreferencesActivity" />
9798
<activity android:name=".activities.PluginManagerActivity" />
9899
<activity android:name=".activities.AboutActivity" />
@@ -221,4 +222,4 @@
221222
android:value="true" />
222223
</service>
223224
</application>
224-
</manifest>
225+
</manifest>

app/src/main/java/com/itsaky/androidide/actions/sidebar/AgentSidebarAction.kt

Lines changed: 0 additions & 25 deletions
This file was deleted.

app/src/main/java/com/itsaky/androidide/activities/MainActivity.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ class MainActivity : EdgeToEdgeIDEActivity() {
307307

308308
internal fun openProject(root: File) {
309309
ProjectManagerImpl.getInstance().projectPath = root.absolutePath
310+
GeneralPreferences.lastOpenedProject = root.absolutePath
310311

311312
// Track project open in Firebase Analytics
312313
analyticsManager.trackProjectOpened(root.absolutePath)

app/src/main/java/com/itsaky/androidide/activities/editor/AgentPanelController.kt

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)