Skip to content

Commit a30c16d

Browse files
committed
Add Configuration
1 parent f967d87 commit a30c16d

3 files changed

Lines changed: 186 additions & 1 deletion

File tree

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
//
2+
// Configuration.swift
3+
// SwiftAndroid
4+
//
5+
// Created by Alsey Coleman Miller on 2/27/26.
6+
//
7+
8+
#if os(Android)
9+
import Android
10+
import AndroidNDK
11+
#endif
12+
13+
/// Wrapper around Android NDK `AConfiguration`.
14+
public struct Configuration: ~Copyable {
15+
16+
internal let pointer: OpaquePointer
17+
18+
internal init(pointer: OpaquePointer) {
19+
self.pointer = pointer
20+
}
21+
22+
deinit {
23+
AConfiguration_delete(pointer)
24+
}
25+
}
26+
27+
// MARK: - Initialization
28+
29+
public extension Configuration {
30+
31+
/// Creates a new, empty configuration object.
32+
init() throws(AndroidFileManagerError) {
33+
guard let pointer = AConfiguration_new() else {
34+
throw .invalidConfiguration
35+
}
36+
self.init(pointer: pointer)
37+
}
38+
39+
/// Creates a configuration populated from the current asset manager state.
40+
init(assetManager: borrowing AssetManager) throws(AndroidFileManagerError) {
41+
try self.init()
42+
AConfiguration_fromAssetManager(pointer, assetManager.pointer)
43+
}
44+
}
45+
46+
// MARK: - Methods
47+
48+
public extension Configuration {
49+
50+
/// Copies all values from another configuration.
51+
func copy(from other: borrowing Configuration) {
52+
AConfiguration_copy(pointer, other.pointer)
53+
}
54+
55+
/// Returns bitmask differences between two configurations.
56+
func diff(_ other: borrowing Configuration) -> Int32 {
57+
AConfiguration_diff(pointer, other.pointer)
58+
}
59+
60+
/// Returns `true` when this configuration matches the requested one.
61+
func matches(_ requested: borrowing Configuration) -> Bool {
62+
AConfiguration_match(pointer, requested.pointer) != 0
63+
}
64+
65+
/// Returns `true` if this configuration is a better match than `base`.
66+
func isBetter(than base: borrowing Configuration, requested: borrowing Configuration) -> Bool {
67+
AConfiguration_isBetterThan(base.pointer, pointer, requested.pointer) != 0
68+
}
69+
}
70+
71+
// MARK: - Properties
72+
73+
public extension Configuration {
74+
75+
var mobileCountryCode: Int32 { AConfiguration_getMcc(pointer) }
76+
var mobileNetworkCode: Int32 { AConfiguration_getMnc(pointer) }
77+
var orientation: Int32 { AConfiguration_getOrientation(pointer) }
78+
var touchscreen: Int32 { AConfiguration_getTouchscreen(pointer) }
79+
var density: Int32 { AConfiguration_getDensity(pointer) }
80+
var keyboard: Int32 { AConfiguration_getKeyboard(pointer) }
81+
var navigation: Int32 { AConfiguration_getNavigation(pointer) }
82+
var keysHidden: Int32 { AConfiguration_getKeysHidden(pointer) }
83+
var navHidden: Int32 { AConfiguration_getNavHidden(pointer) }
84+
var sdkVersion: Int32 { AConfiguration_getSdkVersion(pointer) }
85+
var screenSize: Int32 { AConfiguration_getScreenSize(pointer) }
86+
var screenLong: Int32 { AConfiguration_getScreenLong(pointer) }
87+
var uiModeType: Int32 { AConfiguration_getUiModeType(pointer) }
88+
var uiModeNight: Int32 { AConfiguration_getUiModeNight(pointer) }
89+
var screenWidthDp: Int32 { AConfiguration_getScreenWidthDp(pointer) }
90+
var screenHeightDp: Int32 { AConfiguration_getScreenHeightDp(pointer) }
91+
var smallestScreenWidthDp: Int32 { AConfiguration_getSmallestScreenWidthDp(pointer) }
92+
var layoutDirection: Int32 { AConfiguration_getLayoutDirection(pointer) }
93+
94+
/// ISO 639-1 language code when available.
95+
var languageCode: String? {
96+
var out = [CChar](repeating: 0, count: 2)
97+
AConfiguration_getLanguage(pointer, &out)
98+
return decodeCode(out)
99+
}
100+
101+
/// ISO 3166-1 alpha-2 region code when available.
102+
var countryCode: String? {
103+
var out = [CChar](repeating: 0, count: 2)
104+
AConfiguration_getCountry(pointer, &out)
105+
return decodeCode(out)
106+
}
107+
}
108+
109+
// MARK: - Private
110+
111+
private extension Configuration {
112+
113+
func decodeCode(_ raw: [CChar]) -> String? {
114+
guard raw.count >= 2 else { return nil }
115+
let b0 = UInt8(bitPattern: raw[0])
116+
let b1 = UInt8(bitPattern: raw[1])
117+
guard b0 != 0 || b1 != 0 else {
118+
return nil
119+
}
120+
let bytes = b1 == 0 ? [b0] : [b0, b1]
121+
return String(decoding: bytes, as: UTF8.self)
122+
}
123+
}

Sources/AndroidFileManager/Error.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
/// Android file manager error.
99
public enum AndroidFileManagerError: Swift.Error, Equatable, Sendable {
1010

11+
/// Unable to initialize an `AConfiguration` instance.
12+
case invalidConfiguration
13+
1114
/// Unable to initialize an `AStorageManager` instance.
1215
case invalidStorageManager
1316

@@ -26,4 +29,3 @@ public enum AndroidFileManagerError: Swift.Error, Equatable, Sendable {
2629
/// Error unmounting OBB file (result code).
2730
case unmountObb(Int32)
2831
}
29-

Sources/AndroidFileManager/Syscalls.swift

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,66 @@ func stub() -> Never {
1717
fatalError("Not running on Android")
1818
}
1919

20+
// MARK: - AConfiguration
21+
22+
func AConfiguration_new() -> OpaquePointer? { stub() }
23+
24+
func AConfiguration_delete(_ config: OpaquePointer) { stub() }
25+
26+
func AConfiguration_fromAssetManager(_ out: OpaquePointer, _ am: OpaquePointer) { stub() }
27+
28+
func AConfiguration_copy(_ dest: OpaquePointer, _ src: OpaquePointer) { stub() }
29+
30+
func AConfiguration_diff(_ config1: OpaquePointer, _ config2: OpaquePointer) -> Int32 { stub() }
31+
32+
func AConfiguration_match(_ base: OpaquePointer, _ requested: OpaquePointer) -> Int32 { stub() }
33+
34+
func AConfiguration_isBetterThan(
35+
_ base: OpaquePointer,
36+
_ test: OpaquePointer,
37+
_ requested: OpaquePointer
38+
) -> Int32 { stub() }
39+
40+
func AConfiguration_getMcc(_ config: OpaquePointer) -> Int32 { stub() }
41+
42+
func AConfiguration_getMnc(_ config: OpaquePointer) -> Int32 { stub() }
43+
44+
func AConfiguration_getLanguage(_ config: OpaquePointer, _ outLanguage: UnsafeMutablePointer<CChar>?) { stub() }
45+
46+
func AConfiguration_getCountry(_ config: OpaquePointer, _ outCountry: UnsafeMutablePointer<CChar>?) { stub() }
47+
48+
func AConfiguration_getOrientation(_ config: OpaquePointer) -> Int32 { stub() }
49+
50+
func AConfiguration_getTouchscreen(_ config: OpaquePointer) -> Int32 { stub() }
51+
52+
func AConfiguration_getDensity(_ config: OpaquePointer) -> Int32 { stub() }
53+
54+
func AConfiguration_getKeyboard(_ config: OpaquePointer) -> Int32 { stub() }
55+
56+
func AConfiguration_getNavigation(_ config: OpaquePointer) -> Int32 { stub() }
57+
58+
func AConfiguration_getKeysHidden(_ config: OpaquePointer) -> Int32 { stub() }
59+
60+
func AConfiguration_getNavHidden(_ config: OpaquePointer) -> Int32 { stub() }
61+
62+
func AConfiguration_getSdkVersion(_ config: OpaquePointer) -> Int32 { stub() }
63+
64+
func AConfiguration_getScreenSize(_ config: OpaquePointer) -> Int32 { stub() }
65+
66+
func AConfiguration_getScreenLong(_ config: OpaquePointer) -> Int32 { stub() }
67+
68+
func AConfiguration_getUiModeType(_ config: OpaquePointer) -> Int32 { stub() }
69+
70+
func AConfiguration_getUiModeNight(_ config: OpaquePointer) -> Int32 { stub() }
71+
72+
func AConfiguration_getScreenWidthDp(_ config: OpaquePointer) -> Int32 { stub() }
73+
74+
func AConfiguration_getScreenHeightDp(_ config: OpaquePointer) -> Int32 { stub() }
75+
76+
func AConfiguration_getSmallestScreenWidthDp(_ config: OpaquePointer) -> Int32 { stub() }
77+
78+
func AConfiguration_getLayoutDirection(_ config: OpaquePointer) -> Int32 { stub() }
79+
2080
// MARK: - AAssetManager
2181

2282
func AAssetManager_open(

0 commit comments

Comments
 (0)