soul-browser/sources/java/com/google/api/client/http/GenericUrl.java
KaKi87 550ddb0413
Decompile and recreate Soul Browser v1.4.85 with APK CI builds (#1)
* Decompile and recreate Soul Browser v1.4.85 with APK CI builds

Co-authored-by: KaKi87 <KaKi87@pm.me>

* Fix CI build: include bundled google.jks and remove PR trigger

The apktool build failed in CI because app/unknown/.../google.jks was
excluded by the *.jks gitignore rule. Whitelist app-bundled JKS files
and commit the missing resource.

Also remove the redundant pull_request workflow trigger.

Co-authored-by: KaKi87 <KaKi87@pm.me>

* Change package ID to com.github.kaki87.soulbrowser

Rename the application ID so the rebuilt APK can be installed
alongside the original Soul Browser from Google Play.

- Update AndroidManifest package, permissions, providers, and actions
- Update R class references in smali (com/github/kaki87/soulbrowser/R)
- Update shortcuts.xml targetPackage
- Rename app label to "Soul Rebuild" for easy identification

Co-authored-by: KaKi87 <KaKi87@pm.me>

* Fix install compatibility: remove split APK metadata and bundle native libs

The rebuilt APK still declared requiredSplitTypes and Play Store split
metadata, causing Android to reject standalone installs as incompatible.

- Remove requiredSplitTypes and split-related manifest meta-data
- Merge native libs from all ABI splits with uncompressed storage
- Page-align before signing for extractNativeLibs=false
- Add .so to apktool doNotCompress list

Co-authored-by: KaKi87 <KaKi87@pm.me>

* Fix install failure: use apksigner v2/v3 and bundle arm64 native libs

Target SDK 36 requires APK Signature Scheme v2+, but jarsigner only
produces v1 signatures, causing Android to reject the install.

- Sign with apksigner (v1+v2+v3) instead of jarsigner
- Add arm64-v8a native libraries from universal Soul Browser 1.4.79
- Set extractNativeLibs=true for reliable sideload installs
- Commit stable debug keystore for consistent signatures across builds

Co-authored-by: KaKi87 <KaKi87@pm.me>

* Add committed debug keystore for consistent APK signatures

Co-authored-by: KaKi87 <KaKi87@pm.me>

* Fix startup crash: use original classes2.dex desugar libraries

Apktool recompiles smali_classes2 into a broken classes2.dex, causing
ClassNotFoundException for j$.com.android.tools.r8.a at ML Kit init.

Inject the original classes2.dex (Java 8+ desugar libs) after apktool
build instead of using the recompiled version.

Co-authored-by: KaKi87 <KaKi87@pm.me>

* Fix missing drawable resources from density split APKs

The base APK is an app bundle module; density-specific drawables like
seek_thumb_nor_b live in config.xhdpi.apk and were missing after rebuild,
causing Resources$NotFoundException at runtime.

- Merge non-9-patch resources from split APKs before apktool build
- Sync public.xml IDs from R smali only when backing files exist
- Add 713 density-specific resource IDs to public.xml

Co-authored-by: KaKi87 <KaKi87@pm.me>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-08-10 16:07:14 +02:00

388 lines
11 KiB
Java

package com.google.api.client.http;
import com.google.api.client.util.GenericData;
import com.google.api.client.util.Preconditions;
import com.google.api.client.util.escape.CharEscapers;
import com.google.api.client.util.escape.Escaper;
import com.google.api.client.util.escape.PercentEscaper;
import j$.util.DesugarCollections;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import kotlin.text.Typography;
/* loaded from: classes3.dex */
public class GenericUrl extends GenericData {
private static final Escaper URI_FRAGMENT_ESCAPER = new PercentEscaper("=&-_.!~*'()@:$,;/?:");
private String fragment;
private String host;
private List<String> pathParts;
private int port;
private String scheme;
private String userInfo;
private boolean verbatim;
public GenericUrl() {
this.port = -1;
}
public static void addQueryParams(Set<Map.Entry<String, Object>> set, StringBuilder sb, boolean z) {
String escapeUriQuery;
boolean z2 = true;
for (Map.Entry<String, Object> entry : set) {
Object value = entry.getValue();
if (value != null) {
if (z) {
escapeUriQuery = entry.getKey();
} else {
escapeUriQuery = CharEscapers.escapeUriQuery(entry.getKey());
}
if (value instanceof Collection) {
Iterator it = ((Collection) value).iterator();
while (it.hasNext()) {
z2 = appendParam(z2, sb, escapeUriQuery, it.next(), z);
}
} else {
z2 = appendParam(z2, sb, escapeUriQuery, value, z);
}
}
}
}
private static boolean appendParam(boolean z, StringBuilder sb, String str, Object obj, boolean z2) {
String escapeUriQuery;
if (z) {
sb.append('?');
z = false;
} else {
sb.append(Typography.amp);
}
sb.append(str);
if (z2) {
escapeUriQuery = obj.toString();
} else {
escapeUriQuery = CharEscapers.escapeUriQuery(obj.toString());
}
if (escapeUriQuery.length() != 0) {
sb.append('=');
sb.append(escapeUriQuery);
}
return z;
}
private void appendRawPathFromParts(StringBuilder sb) {
int size = this.pathParts.size();
for (int i = 0; i < size; i++) {
String str = this.pathParts.get(i);
if (i != 0) {
sb.append('/');
}
if (str.length() != 0) {
if (!this.verbatim) {
str = CharEscapers.escapeUriPath(str);
}
sb.append(str);
}
}
}
private static URL parseURL(String str) {
try {
return new URL(str);
} catch (MalformedURLException e) {
throw new IllegalArgumentException(e);
}
}
public static List<String> toPathParts(String str) {
return toPathParts(str, false);
}
public void appendRawPath(String str) {
if (str != null && str.length() != 0) {
List<String> pathParts = toPathParts(str, this.verbatim);
List<String> list = this.pathParts;
if (list != null && !list.isEmpty()) {
int size = this.pathParts.size();
int i = size - 1;
this.pathParts.set(i, this.pathParts.get(i) + pathParts.get(0));
this.pathParts.addAll(pathParts.subList(1, pathParts.size()));
return;
}
this.pathParts = pathParts;
}
}
public final String build() {
return buildAuthority() + buildRelativeUrl();
}
public final String buildAuthority() {
StringBuilder sb = new StringBuilder();
sb.append((String) Preconditions.checkNotNull(this.scheme));
sb.append("://");
String str = this.userInfo;
if (str != null) {
if (!this.verbatim) {
str = CharEscapers.escapeUriUserInfo(str);
}
sb.append(str);
sb.append('@');
}
sb.append((String) Preconditions.checkNotNull(this.host));
int i = this.port;
if (i != -1) {
sb.append(':');
sb.append(i);
}
return sb.toString();
}
public final String buildRelativeUrl() {
StringBuilder sb = new StringBuilder();
if (this.pathParts != null) {
appendRawPathFromParts(sb);
}
addQueryParams(entrySet(), sb, this.verbatim);
String str = this.fragment;
if (str != null) {
sb.append('#');
if (!this.verbatim) {
str = URI_FRAGMENT_ESCAPER.escape(str);
}
sb.append(str);
}
return sb.toString();
}
@Override // com.google.api.client.util.GenericData, java.util.AbstractMap, java.util.Map
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (super.equals(obj) && (obj instanceof GenericUrl)) {
return build().equals(((GenericUrl) obj).build());
}
return false;
}
public Collection<Object> getAll(String str) {
Object obj = get(str);
if (obj == null) {
return Collections.EMPTY_SET;
}
if (obj instanceof Collection) {
return DesugarCollections.unmodifiableCollection((Collection) obj);
}
return Collections.singleton(obj);
}
public Object getFirst(String str) {
Object obj = get(str);
if (obj instanceof Collection) {
Iterator it = ((Collection) obj).iterator();
if (it.hasNext()) {
return it.next();
}
return null;
}
return obj;
}
public String getFragment() {
return this.fragment;
}
public String getHost() {
return this.host;
}
public List<String> getPathParts() {
return this.pathParts;
}
public int getPort() {
return this.port;
}
public String getRawPath() {
if (this.pathParts == null) {
return null;
}
StringBuilder sb = new StringBuilder();
appendRawPathFromParts(sb);
return sb.toString();
}
public final String getScheme() {
return this.scheme;
}
public final String getUserInfo() {
return this.userInfo;
}
@Override // com.google.api.client.util.GenericData, java.util.AbstractMap, java.util.Map
public int hashCode() {
return build().hashCode();
}
public final void setFragment(String str) {
this.fragment = str;
}
public final void setHost(String str) {
this.host = (String) Preconditions.checkNotNull(str);
}
public void setPathParts(List<String> list) {
this.pathParts = list;
}
public final void setPort(int i) {
boolean z;
if (i >= -1) {
z = true;
} else {
z = false;
}
Preconditions.checkArgument(z, "expected port >= -1");
this.port = i;
}
public void setRawPath(String str) {
this.pathParts = toPathParts(str, this.verbatim);
}
public final void setScheme(String str) {
this.scheme = (String) Preconditions.checkNotNull(str);
}
public final void setUserInfo(String str) {
this.userInfo = str;
}
@Override // com.google.api.client.util.GenericData, java.util.AbstractMap
public String toString() {
return build();
}
public final URI toURI() {
return toURI(build());
}
public final URL toURL() {
return parseURL(build());
}
public static List<String> toPathParts(String str, boolean z) {
String substring;
if (str == null || str.length() == 0) {
return null;
}
ArrayList arrayList = new ArrayList();
int i = 0;
boolean z2 = true;
while (z2) {
int indexOf = str.indexOf(47, i);
boolean z3 = indexOf != -1;
if (z3) {
substring = str.substring(i, indexOf);
} else {
substring = str.substring(i);
}
if (!z) {
substring = CharEscapers.decodeUriPath(substring);
}
arrayList.add(substring);
i = indexOf + 1;
z2 = z3;
}
return arrayList;
}
private static URI toURI(String str) {
try {
return new URI(str);
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
}
@Override // com.google.api.client.util.GenericData
public GenericUrl set(String str, Object obj) {
return (GenericUrl) super.set(str, obj);
}
public final URL toURL(String str) {
try {
return new URL(toURL(), str);
} catch (MalformedURLException e) {
throw new IllegalArgumentException(e);
}
}
public GenericUrl(String str) {
this(str, false);
}
@Override // com.google.api.client.util.GenericData, java.util.AbstractMap
public GenericUrl clone() {
GenericUrl genericUrl = (GenericUrl) super.clone();
if (this.pathParts != null) {
genericUrl.pathParts = new ArrayList(this.pathParts);
}
return genericUrl;
}
public GenericUrl(String str, boolean z) {
this(parseURL(str), z);
}
public GenericUrl(URI uri) {
this(uri, false);
}
public GenericUrl(URI uri, boolean z) {
this(uri.getScheme(), uri.getHost(), uri.getPort(), uri.getRawPath(), uri.getRawFragment(), uri.getRawQuery(), uri.getRawUserInfo(), z);
}
public GenericUrl(URL url) {
this(url, false);
}
public GenericUrl(URL url, boolean z) {
this(url.getProtocol(), url.getHost(), url.getPort(), url.getPath(), url.getRef(), url.getQuery(), url.getUserInfo(), z);
}
private GenericUrl(String str, String str2, int i, String str3, String str4, String str5, String str6, boolean z) {
this.port = -1;
this.scheme = str.toLowerCase(Locale.US);
this.host = str2;
this.port = i;
this.pathParts = toPathParts(str3, z);
this.verbatim = z;
if (z) {
this.fragment = str4;
if (str5 != null) {
UrlEncodedParser.parse(str5, (Object) this, false);
}
this.userInfo = str6;
return;
}
this.fragment = str4 != null ? CharEscapers.decodeUri(str4) : null;
if (str5 != null) {
UrlEncodedParser.parse(str5, this);
}
this.userInfo = str6 != null ? CharEscapers.decodeUri(str6) : null;
}
}