Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ let package = Package(
dependencies: [
"AndroidFileManager"
]),
.testTarget(
name: "AndroidConfigurationTests",
dependencies: [
"AndroidFileManager"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why you changed "AndroidAssetManager" to "AndroidFileManager"? I think either is fine, but assets and files aren't really the same thing…

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the reason was to make it encompass the AssetManager, StorageManager (ObbFiles) and the Configuration which for some reason is tied to AssetManager. I felt AndroidFileManager was generic enough for those 3 types. We could break it into 3 targets but they all seem related to file management.

]),
.target(
name: "AndroidContext",
dependencies: [
Expand Down
10 changes: 5 additions & 5 deletions Sources/AndroidFileManager/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,16 @@ public struct Configuration: ~Copyable {
public extension Configuration {

/// Creates a new, empty configuration object.
init() throws(AndroidFileManagerError) {
init() {
guard let pointer = AConfiguration_new() else {
throw .invalidConfiguration
fatalError("AConfiguration_new() failed")
Comment thread
colemancda marked this conversation as resolved.
}
self.init(pointer: pointer)
}

/// Creates a configuration populated from the current asset manager state.
init(assetManager: borrowing AssetManager) throws(AndroidFileManagerError) {
try self.init()
init(assetManager: borrowing AssetManager) {
self.init()
AConfiguration_fromAssetManager(pointer, assetManager.pointer)
}
}
Expand Down Expand Up @@ -192,7 +192,7 @@ public extension Configuration {
@available(Android 30, *)
var screenRound: ScreenRound {
get { ScreenRound(rawValue: AConfiguration_getScreenRound(pointer)) ?? .any }
set { AConfiguration_setScreenRound(pointer, newValue.rawValue) }
//set { AConfiguration_setScreenRound(pointer, newValue.rawValue) }
Comment thread
colemancda marked this conversation as resolved.
}

/// UI mode type (car, desk, television, etc.).
Expand Down
6 changes: 0 additions & 6 deletions Sources/AndroidFileManager/Error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@
/// Android file manager error.
public enum AndroidFileManagerError: Swift.Error, Equatable, Sendable {

/// Unable to initialize an `AConfiguration` instance.
case invalidConfiguration

/// Unable to initialize an `AStorageManager` instance.
case invalidStorageManager

/// Unable to open asset at the specified path.
case openAsset(String)

Expand Down
4 changes: 2 additions & 2 deletions Sources/AndroidFileManager/ObbFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ public actor ObbFile {
/// - Parameter path: The path to the OBB file.
/// - Throws: `AndroidFileManagerError.invalidStorageManager` if the underlying
/// `AStorageManager` instance could not be created.
public init(path: String) throws(AndroidFileManagerError) {
let manager = try StorageManager()
public init(path: String) {
let manager = StorageManager()
self.init(path: path, manager: manager)
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/AndroidFileManager/StorageManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ public struct StorageManager: ~Copyable, @unchecked Sendable {
public extension StorageManager {

/// Creates an `AStorageManager` instance.
init() throws(AndroidFileManagerError) {
init() {
guard let handle = Handle.create() else {
throw .invalidStorageManager
fatalError("AStorageManager_new() failed")
}
self.init(handle)
}
Expand Down
138 changes: 138 additions & 0 deletions Tests/AndroidConfigurationTests/AndroidConfigurationTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAndroidNative open source project
//
// Copyright (c) 2024-2026 Skip.dev and SwiftAndroidNative project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftAndroidNative project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import Testing
import AndroidFileManager

struct AndroidConfigurationTests {

@Test func testProperties() throws {
var config = Configuration()

config.mobileCountryCode = 310
#expect(config.mobileCountryCode == 310)

config.mobileNetworkCode = 260
#expect(config.mobileNetworkCode == 260)

config.languageCode = "en"
#expect(config.languageCode == "en")

config.countryCode = "US"
#expect(config.countryCode == "US")

config.orientation = .portrait
#expect(config.orientation == .portrait)

config.touchscreen = .finger
#expect(config.touchscreen == .finger)

config.density = .xHigh
#expect(config.density == .xHigh)

config.keyboard = .qwerty
#expect(config.keyboard == .qwerty)

config.navigation = .dpad
#expect(config.navigation == .dpad)

config.keysHidden = .hidden
#expect(config.keysHidden == .hidden)

config.navHidden = .hidden
#expect(config.navHidden == .hidden)

config.sdkVersion = 33
#expect(config.sdkVersion == 33)

config.screenSize = .large
#expect(config.screenSize == .large)

config.screenLong = .long
#expect(config.screenLong == .long)

config.uiModeType = .normal
#expect(config.uiModeType == .normal)

config.uiModeNight = .dark
#expect(config.uiModeNight == .dark)

config.screenWidthDp = 1080
#expect(config.screenWidthDp == 1080)

config.screenHeightDp = 1920
#expect(config.screenHeightDp == 1920)

config.smallestScreenWidthDp = 360
#expect(config.smallestScreenWidthDp == 360)

if #available(Android 17, *) {
config.layoutDirection = .rightToLeft
#expect(config.layoutDirection == .rightToLeft)
}

if #available(Android 30, *) {
//config.screenRound = .round
#expect(config.screenRound == .any)
}

if #available(Android 34, *) {
config.grammaticalGender = .feminine
#expect(config.grammaticalGender == .feminine)
}
}

@Test func testMatches() throws {
// Two default configurations should match each other
let a = Configuration()
let b = Configuration()
let defaultsMatch = a.matches(b)
#expect(defaultsMatch)

// A portrait configuration should match a portrait request
var portrait = Configuration()
portrait.orientation = .portrait
var requestedPortrait = Configuration()
requestedPortrait.orientation = .portrait
let portraitMatch = portrait.matches(requestedPortrait)
#expect(portraitMatch)

// A portrait configuration should not match a landscape request
var requestedLandscape = Configuration()
requestedLandscape.orientation = .landscape
let landscapeMismatch = portrait.matches(requestedLandscape)
#expect(!landscapeMismatch)
}

@Test func testDiff() throws {
// Two default configurations should have no differences
let a = Configuration()
let b = Configuration()
let zeroDiff = a.diff(b)
#expect(zeroDiff == 0)

// Configurations differing by MCC should produce a non-zero diff
var c = Configuration()
c.mobileCountryCode = 310
let mccDiff = a.diff(c)
#expect(mccDiff != 0)

// Multiple differing fields should each contribute to the diff mask
var d = Configuration()
d.orientation = .landscape
d.uiModeNight = .dark
let mask = a.diff(d)
#expect(mask != 0)
}
}
Loading