Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement ADB, Accessibility tests #110

Merged
merged 1 commit into from
Sep 8, 2024
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,4 @@ fastlane/test_output

iOSInjectionProject/

.DS_Store
.DS_Store
24 changes: 24 additions & 0 deletions MiniSim.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
76059BF52AD4361C0008D38B /* SetupPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76059BF42AD4361C0008D38B /* SetupPreferences.swift */; };
76059BF72AD449DC0008D38B /* OnboardingHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76059BF62AD449DC0008D38B /* OnboardingHeader.swift */; };
76059BF92AD558C30008D38B /* SetupItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76059BF82AD558C30008D38B /* SetupItemView.swift */; };
760DEACE2B0DFB6600253576 /* ShellStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 760DEACD2B0DFB6600253576 /* ShellStub.swift */; };
7610992D2A3F95850067885A /* MiniSim.sdef in Resources */ = {isa = PBXBuildFile; fileRef = 7610992C2A3F95850067885A /* MiniSim.sdef */; };
7610992F2A3F95D90067885A /* NSScriptCommand+utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7610992E2A3F95D90067885A /* NSScriptCommand+utils.swift */; };
7625140B2992B46D0060A225 /* Pasteboard+utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7625140A2992B46D0060A225 /* Pasteboard+utils.swift */; };
Expand Down Expand Up @@ -75,8 +76,11 @@
76AC9AF62A0EA82C00864A8B /* CustomCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76AC9AF52A0EA82C00864A8B /* CustomCommands.swift */; };
76AC9AF92A0EB50800864A8B /* SymbolPicker in Frameworks */ = {isa = PBXBuildFile; productRef = 76AC9AF82A0EB50800864A8B /* SymbolPicker */; };
76B70F7E2B0D361A009D87A4 /* UserDefaultsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76B70F7D2B0D361A009D87A4 /* UserDefaultsTests.swift */; };
76B70F822B0D50FE009D87A4 /* ADBTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76B70F812B0D50FE009D87A4 /* ADBTests.swift */; };
76B70F842B0D5AB4009D87A4 /* Shell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76B70F832B0D5AB4009D87A4 /* Shell.swift */; };
76BF0AD92C8CB3E6003BE568 /* AcknowList in Frameworks */ = {isa = PBXBuildFile; productRef = 76BF0AD82C8CB3E6003BE568 /* AcknowList */; };
76BF0ADB2C8CB4CD003BE568 /* Package.resolved in Resources */ = {isa = PBXBuildFile; fileRef = 76BF0ADA2C8CB4CD003BE568 /* Package.resolved */; };
76BF0ADD2C8DF660003BE568 /* AccessibilityElementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76BF0ADC2C8DF660003BE568 /* AccessibilityElementTests.swift */; };
76C1396A2C849A3F006CD80C /* MenuIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76C139692C849A3F006CD80C /* MenuIcons.swift */; };
76E4451229D4391000039025 /* Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76E4451129D4391000039025 /* Onboarding.swift */; };
76E4451429D4403F00039025 /* NSNotificationName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76E4451329D4403F00039025 /* NSNotificationName.swift */; };
Expand Down Expand Up @@ -115,6 +119,7 @@
76059BF42AD4361C0008D38B /* SetupPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupPreferences.swift; sourceTree = "<group>"; };
76059BF62AD449DC0008D38B /* OnboardingHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingHeader.swift; sourceTree = "<group>"; };
76059BF82AD558C30008D38B /* SetupItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupItemView.swift; sourceTree = "<group>"; };
760DEACD2B0DFB6600253576 /* ShellStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShellStub.swift; sourceTree = "<group>"; };
7610992C2A3F95850067885A /* MiniSim.sdef */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = MiniSim.sdef; sourceTree = "<group>"; };
7610992E2A3F95D90067885A /* NSScriptCommand+utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSScriptCommand+utils.swift"; sourceTree = "<group>"; };
7625140A2992B46D0060A225 /* Pasteboard+utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Pasteboard+utils.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -169,7 +174,10 @@
76AC9AF52A0EA82C00864A8B /* CustomCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomCommands.swift; sourceTree = "<group>"; };
76B70F742B0D359D009D87A4 /* MiniSimTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MiniSimTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
76B70F7D2B0D361A009D87A4 /* UserDefaultsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsTests.swift; sourceTree = "<group>"; };
76B70F812B0D50FE009D87A4 /* ADBTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ADBTests.swift; sourceTree = "<group>"; };
76B70F832B0D5AB4009D87A4 /* Shell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shell.swift; sourceTree = "<group>"; };
76BF0ADA2C8CB4CD003BE568 /* Package.resolved */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Package.resolved; path = MiniSim.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved; sourceTree = SOURCE_ROOT; };
76BF0ADC2C8DF660003BE568 /* AccessibilityElementTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityElementTests.swift; sourceTree = "<group>"; };
76C139692C849A3F006CD80C /* MenuIcons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuIcons.swift; sourceTree = "<group>"; };
76E4451129D4391000039025 /* Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Onboarding.swift; sourceTree = "<group>"; };
76E4451329D4403F00039025 /* NSNotificationName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSNotificationName.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -230,6 +238,14 @@
path = Terminal;
sourceTree = "<group>";
};
760DEACC2B0DFB5B00253576 /* Mocks */ = {
isa = PBXGroup;
children = (
760DEACD2B0DFB6600253576 /* ShellStub.swift */,
);
path = Mocks;
sourceTree = "<group>";
};
762CF1E12981DDD400099999 /* Extensions */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -297,6 +313,7 @@
7645D4BD2982A1B100019227 /* DeviceService.swift */,
7699511C2C845B1900462287 /* DeviceParser.swift */,
76F04A10298A5AE000BF9CA3 /* ADB.swift */,
76B70F832B0D5AB4009D87A4 /* Shell.swift */,
);
path = Service;
sourceTree = "<group>";
Expand Down Expand Up @@ -396,8 +413,11 @@
76B70F752B0D359D009D87A4 /* MiniSimTests */ = {
isa = PBXGroup;
children = (
760DEACC2B0DFB5B00253576 /* Mocks */,
76B70F7D2B0D361A009D87A4 /* UserDefaultsTests.swift */,
7699511E2C845CBA00462287 /* DeviceParserTests.swift */,
76B70F812B0D50FE009D87A4 /* ADBTests.swift */,
76BF0ADC2C8DF660003BE568 /* AccessibilityElementTests.swift */,
);
path = MiniSimTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -619,6 +639,7 @@
7630B2752986D52900D8B57D /* NSAlert+showError.swift in Sources */,
4AFACC742AD730BE00EC369F /* SubMenuItem.swift in Sources */,
7630B25E2984339100D8B57D /* MainMenuActions.swift in Sources */,
76B70F842B0D5AB4009D87A4 /* Shell.swift in Sources */,
76AC9AF62A0EA82C00864A8B /* CustomCommands.swift in Sources */,
76489D5C29BFCA330070EF03 /* OnboardingItem.swift in Sources */,
7645D5012982E6FA00019227 /* main.swift in Sources */,
Expand Down Expand Up @@ -656,7 +677,10 @@
buildActionMask = 2147483647;
files = (
7699511F2C845CBA00462287 /* DeviceParserTests.swift in Sources */,
76BF0ADD2C8DF660003BE568 /* AccessibilityElementTests.swift in Sources */,
76B70F7E2B0D361A009D87A4 /* UserDefaultsTests.swift in Sources */,
760DEACE2B0DFB6600253576 /* ShellStub.swift in Sources */,
76B70F822B0D50FE009D87A4 /* ADBTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
5 changes: 3 additions & 2 deletions MiniSim/AccessibilityElement.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
//

import AppKit
import ShellOut

class AccessibilityElement {
static var shell: ShellProtocol = Shell()

private let underlyingElement: AXUIElement

required init(_ axUIElement: AXUIElement) {
Expand Down Expand Up @@ -44,7 +45,7 @@ class AccessibilityElement {
set frontmost of every process whose unix id is \(pid) to true
end tell'
"""
_ = try? shellOut(to: script)
_ = try? shell.execute(command: script)
}
}

Expand Down
55 changes: 43 additions & 12 deletions MiniSim/Service/Adb.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,24 @@
//

import Foundation
import ShellOut

protocol ADBProtocol {
static var shell: ShellProtocol { get set }

static func getAdbPath() throws -> String
static func getEmulatorPath() throws -> String
static func getAdbId(for deviceName: String, adbPath: String) throws -> String
static func checkAndroidHome(path: String) throws -> Bool
static func isAccesibilityOn(deviceId: String, adbPath: String) -> Bool
static func getAdbId(for deviceName: String) throws -> String
static func checkAndroidHome(
path: String,
fileManager: FileManager
) throws -> Bool
static func isAccesibilityOn(deviceId: String) -> Bool
static func toggleAccesibility(deviceId: String)
}

final class ADB: ADBProtocol {
static var shell: ShellProtocol = Shell()

static let talkbackOn = "com.google.android.marvin.talkback/com.google.android.marvin.talkback.TalkBackService"
static let talkbackOff = "com.android.talkback/com.google.android.marvin.talkback.TalkBackService"

Expand Down Expand Up @@ -55,13 +62,16 @@ final class ADB: ADBProtocol {
/**
Checks if passed path exists and points to `ANDROID_HOME`.
*/
@discardableResult static func checkAndroidHome(path: String) throws -> Bool {
if !FileManager.default.fileExists(atPath: path) {
@discardableResult static func checkAndroidHome(
path: String,
fileManager: FileManager = .default
) throws -> Bool {
if !fileManager.fileExists(atPath: path) {
throw AndroidHomeError.pathNotFound
}

do {
try shellOut(to: "\(path)" + Paths.emulator.rawValue, arguments: ["-list-avds"])
try shell.execute(command: "\(path)" + Paths.emulator.rawValue, arguments: ["-list-avds"])
} catch {
throw AndroidHomeError.pathNotCorrect
}
Expand All @@ -72,14 +82,20 @@ final class ADB: ADBProtocol {
try getAndroidHome() + Paths.emulator.rawValue
}

static func getAdbId(for deviceName: String, adbPath: String) throws -> String {
let onlineDevices = try shellOut(to: "\(adbPath) devices")
static func getAdbId(for deviceName: String) throws -> String {
let adbPath = try Self.getAdbPath()
let onlineDevices = try shell.execute(command: "\(adbPath) devices")
let splitted = onlineDevices.components(separatedBy: "\n")

for line in splitted {
let device = line.match("^emulator-[0-9]+")
guard let deviceId = device.first?.first else { continue }
let output = try? shellOut(to: "\(adbPath) -s \(deviceId) emu avd name").components(separatedBy: "\n")

let output = try? shell.execute(
command: "\(adbPath) -s \(deviceId) emu avd name"
)
.components(separatedBy: "\n")

if let name = output?.first {
let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
let trimmedDeviceName = deviceName.trimmingCharacters(in: .whitespacesAndNewlines)
Expand All @@ -91,9 +107,12 @@ final class ADB: ADBProtocol {
throw DeviceError.deviceNotFound
}

static func isAccesibilityOn(deviceId: String, adbPath: String) -> Bool {
static func isAccesibilityOn(deviceId: String) -> Bool {
guard let adbPath = try? Self.getAdbPath() else {
return false
}
let shellCommand = "\(adbPath) -s \(deviceId) shell settings get secure enabled_accessibility_services"
guard let result = try? shellOut(to: [shellCommand]) else {
guard let result = try? shell.execute(command: shellCommand) else {
return false
}

Expand All @@ -103,4 +122,16 @@ final class ADB: ADBProtocol {

return false
}

static func toggleAccesibility(deviceId: String) {
guard let adbPath = try? Self.getAdbPath() else {
return
}
let a11yIsEnabled = Self.isAccesibilityOn(deviceId: deviceId)
let value = a11yIsEnabled ? ADB.talkbackOff : ADB.talkbackOn
let shellCmd = "\(adbPath) -s \(deviceId) shell settings put secure enabled_accessibility_services \(value)"

// Ignore the error if toggling a11y fails.
_ = try? shell.execute(command: shellCmd)
}
}
3 changes: 1 addition & 2 deletions MiniSim/Service/DeviceParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,11 @@ class AndroidEmulatorParser: DeviceParser {
}

func parse(_ input: String) -> [Device] {
guard let adbPath = try? adb.getAdbPath() else { return [] }
let deviceNames = input.components(separatedBy: .newlines)
return deviceNames
.filter { !$0.isEmpty && !$0.contains("Storing crashdata") }
.compactMap { deviceName in
let adbId = try? adb.getAdbId(for: deviceName, adbPath: adbPath)
let adbId = try? adb.getAdbId(for: deviceName)
return Device(name: deviceName, identifier: adbId, booted: adbId != nil, platform: .android, type: .virtual)
}
}
Expand Down
2 changes: 1 addition & 1 deletion MiniSim/Service/DeviceService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@
try shellOut(to: ProcessPaths.xcrun.rawValue, arguments: ["simctl", "delete", uuid])
}

static func handleiOSAction(device: Device, commandTag: SubMenuItems.Tags, itemName: String) {

Check warning on line 301 in MiniSim/Service/DeviceService.swift

View workflow job for this annotation

GitHub Actions / lint

Cyclomatic Complexity Violation: Function should have complexity 10 or less; currently complexity is 11 (cyclomatic_complexity)
queue.async {
switch commandTag {
case .copyName:
Expand Down Expand Up @@ -406,7 +406,7 @@
throw DeviceError.deviceNotFound
}

let a11yIsEnabled = ADB.isAccesibilityOn(deviceId: adbId, adbPath: adbPath)
let a11yIsEnabled = ADB.isAccesibilityOn(deviceId: adbId)
let value = a11yIsEnabled ? ADB.talkbackOff : ADB.talkbackOn
let shellCmd = "\(adbPath) -s \(adbId) shell settings put secure enabled_accessibility_services \(value)"
_ = try? shellOut(to: shellCmd)
Expand Down Expand Up @@ -448,7 +448,7 @@
try TerminalService.launchTerminal(command: logcatCommand)
}

static func handleAndroidAction(device: Device, commandTag: SubMenuItems.Tags, itemName: String) {

Check warning on line 451 in MiniSim/Service/DeviceService.swift

View workflow job for this annotation

GitHub Actions / lint

Cyclomatic Complexity Violation: Function should have complexity 10 or less; currently complexity is 15 (cyclomatic_complexity)

Check warning on line 451 in MiniSim/Service/DeviceService.swift

View workflow job for this annotation

GitHub Actions / lint

Function Body Length Violation: Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines (function_body_length)
queue.async {
do {
switch commandTag {
Expand Down Expand Up @@ -508,4 +508,4 @@
}
}
}
}

Check warning on line 511 in MiniSim/Service/DeviceService.swift

View workflow job for this annotation

GitHub Actions / lint

File Length Violation: File should contain 400 lines or less: currently contains 511 (file_length)
34 changes: 34 additions & 0 deletions MiniSim/Service/Shell.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Foundation
import ShellOut

protocol ShellProtocol {
@discardableResult func execute(
command: String,
arguments: [String],
atPath: String
) throws -> String
}

extension ShellProtocol {
@discardableResult func execute(
command: String,
arguments: [String] = [],
atPath: String = "."
) throws -> String {
try execute(command: command, arguments: arguments, atPath: atPath)
}
}

final class Shell: ShellProtocol {
@discardableResult func execute(
command: String,
arguments: [String] = [],
atPath: String = "."
) throws -> String {
try shellOut(
to: command,
arguments: arguments,
at: atPath
)
}
}
12 changes: 6 additions & 6 deletions MiniSim/Views/About.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,28 @@
// Created by Oskar Kwaśniewski on 28/01/2023.
//

import AcknowList
import Sparkle
import SwiftUI
import AcknowList

struct About: View {
private let updaterController: SPUStandardUpdaterController
@Environment (\.openURL) private var openURL
@State private var isAcknowledgementsListPresented = false

init() {
updaterController = SPUStandardUpdaterController(
startingUpdater: true,
updaterDelegate: nil,
userDriverDelegate: nil
)
}

let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
private let bottomPadding: Double = 10
private let minFrameWidth: Double = 650
private let minFrameHeight: Double = 450

var body: some View {
VStack {
Image(nsImage: NSImage(named: "AppIcon") ?? NSImage())
Expand All @@ -42,11 +42,11 @@
Label("Check for updates", systemImage: "gear")
}
.padding(.bottom, bottomPadding)

Button("Acknowledgements") {
isAcknowledgementsListPresented.toggle()
}

HStack {
Button("GitHub") {
openURL(URL(string: "https://github.com/okwasniewski/MiniSim")!)
Expand All @@ -58,7 +58,7 @@
Link("Created by Oskar Kwaśniewski", destination: URL(string: "https://github.com/okwasniewski")!)
.font(.caption)
}
.sheet(isPresented: $isAcknowledgementsListPresented, content: {

Check warning on line 61 in MiniSim/Views/About.swift

View workflow job for this annotation

GitHub Actions / lint

Trailing Closure Violation: Trailing closure syntax should be used whenever possible (trailing_closure)
NavigationView {
AcknowListSwiftUIView(acknowList: AcknowParser.defaultPackages()!)
.toolbar {
Expand Down
1 change: 0 additions & 1 deletion MiniSim/Views/Onboarding/SetupView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// Created by Oskar Kwaśniewski on 15/03/2023.
//

import ShellOut
import SwiftUI

struct SetupView: View {
Expand Down
1 change: 0 additions & 1 deletion MiniSim/Views/Preferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import KeyboardShortcuts
import LaunchAtLogin
import Settings
import ShellOut
import SwiftUI

struct Preferences: View {
Expand Down
Loading
Loading