1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'dart:io' as io;
6
7import 'package:path/path.dart' as path;
8import 'package:pub_semver/pub_semver.dart';
9
10String adbPath() {
11 final String? androidHome =
12 io.Platform.environment['ANDROID_HOME'] ?? io.Platform.environment['ANDROID_SDK_ROOT'];
13 if (androidHome == null) {
14 return 'adb';
15 } else {
16 return path.join(androidHome, 'platform-tools', 'adb');
17 }
18}
19
20Future<Version> getTalkbackVersion() async {
21 final io.ProcessResult result = await io.Process.run(adbPath(), const <String>[
22 'shell',
23 'dumpsys',
24 'package',
25 'com.google.android.marvin.talkback',
26 ]);
27 if (result.exitCode != 0) {
28 throw Exception(
29 'Failed to get TalkBack version: ${result.stdout as String}\n${result.stderr as String}',
30 );
31 }
32 final List<String> lines = (result.stdout as String).split('\n');
33 String? version;
34 for (final String line in lines) {
35 if (line.contains('versionName')) {
36 version = line.replaceAll(RegExp(r'\s*versionName='), '');
37 break;
38 }
39 }
40 if (version == null) {
41 throw Exception('Unable to determine TalkBack version.');
42 }
43
44 // Android doesn't quite use semver, so convert the version string to semver form.
45 final RegExp startVersion = RegExp(
46 r'(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(\.(?<build>\d+))?',
47 );
48 final RegExpMatch? match = startVersion.firstMatch(version);
49 if (match == null) {
50 return Version(0, 0, 0);
51 }
52 return Version(
53 int.parse(match.namedGroup('major')!),
54 int.parse(match.namedGroup('minor')!),
55 int.parse(match.namedGroup('patch')!),
56 build: match.namedGroup('build'),
57 );
58}
59
60Future<void> enableTalkBack() async {
61 final io.Process run = await io.Process.start(adbPath(), const <String>[
62 'shell',
63 'settings',
64 'put',
65 'secure',
66 'enabled_accessibility_services',
67 'com.google.android.marvin.talkback/com.google.android.marvin.talkback.TalkBackService',
68 ]);
69 await run.exitCode;
70
71 print('TalkBack version is ${await getTalkbackVersion()}');
72}
73
74Future<void> disableTalkBack() async {
75 final io.Process run = await io.Process.start(adbPath(), const <String>[
76 'shell',
77 'settings',
78 'put',
79 'secure',
80 'enabled_accessibility_services',
81 'null',
82 ]);
83 await run.exitCode;
84}
85