-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgetcutout.py
executable file
·193 lines (149 loc) · 6.22 KB
/
getcutout.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-only
# Copyright (C) 2023 Bardia Moshiri <[email protected]>
import os
import sys
import re
import json
import fnmatch
import subprocess
import argparse
from svg.path import Path, Line, Arc, CubicBezier, QuadraticBezier, parse_path
parser = argparse.ArgumentParser(description="Create JSON representation of device cutouts and border radius.")
parser.add_argument("-o", "--output", required=True, help="Path to the output JSON file")
args = parser.parse_args()
if os.getuid() != 0:
print("must run as root, exiting")
sys.exit(1)
def read_screen_size():
height_file = '/var/lib/droidian/phosh-notch/height'
width_file = '/var/lib/droidian/phosh-notch/width'
try:
with open(height_file, 'r') as f:
height = int(f.read().strip())
except Exception as e:
print(f"Failed to read height from {height_file}, Error: {str(e)}")
sys.exit(1)
try:
with open(width_file, 'r') as f:
width = int(f.read().strip())
except Exception as e:
print(f"Failed to read width from {width_file}, Error: {str(e)}")
sys.exit(1)
return height, width
height, width = read_screen_size()
def parse_svg_string(svg_string, width):
target_x = width / 2
if '@right' in svg_string:
target_x = width * 90 / 100
svg_string = svg_string.replace('@right', '')
elif '@left' in svg_string:
target_x = width * 10 / 100
svg_string = svg_string.replace('@left', '')
return svg_string, target_x
def reposition_svg(svg_string, width):
svg_string, target_x = parse_svg_string(svg_string, width)
m_position = svg_string.find('M')
if m_position == -1:
m_position = svg_string.find('m')
# If 'M' or 'm' is found, extract the substring from that position onwards
if m_position != -1:
svg_string = svg_string[m_position:]
path_d_match = re.search('M(.*?)Z', svg_string, re.IGNORECASE)
if path_d_match is None:
print('No matching path found in SVG string')
return None
path_d = path_d_match.group(0)
path = parse_path(path_d)
x_coordinates = [point.real for segment in path for point in [segment.start, segment.end]]
min_x, max_x = min(x_coordinates), max(x_coordinates)
current_center_x = (min_x + max_x) / 2
shift_distance = target_x - current_center_x
new_path = Path()
for segment in path:
if isinstance(segment, Line):
new_segment = Line(segment.start + complex(shift_distance, 0), segment.end + complex(shift_distance, 0))
elif isinstance(segment, CubicBezier):
new_segment = CubicBezier(segment.start + complex(shift_distance, 0), segment.control1 + complex(shift_distance, 0), segment.control2 + complex(shift_distance, 0), segment.end + complex(shift_distance, 0))
elif isinstance(segment, QuadraticBezier):
new_segment = QuadraticBezier(segment.start + complex(shift_distance, 0), segment.control + complex(shift_distance, 0), segment.end + complex(shift_distance, 0))
else:
continue
new_path.append(new_segment)
return new_path.d()
def extract_value_from_prop(file, prop):
with open(file, 'r') as f:
for line in f:
if line.startswith(prop):
return line.split('=')[1].strip()
def get_cutout(rro_file):
command = ['getoverlay', '-p', rro_file, '-c', 'config_mainBuiltInDisplayCutout']
cutout_bytes = subprocess.check_output(command)
cutout = cutout_bytes.decode('utf-8', 'ignore').strip()
if "Failed to get value" in cutout:
return None
return cutout
def find_apk_with_properties(root_dir):
for root, dirs, files in os.walk(root_dir):
dirs[:] = [d for d in dirs if not 'emulation' in d.lower()]
files = [f for f in files if not 'emulation' in f.lower()]
for filename in files:
if filename.endswith('.apk'):
rro_file = os.path.join(root, filename)
cutout_test = subprocess.check_output(['getoverlay', '-p', rro_file, '-c', 'config_mainBuiltInDisplayCutout']).decode('utf-8', 'ignore').strip()
# decode to utf-8 and ignore anything we can't use, overlay-reader might return useless characters ^^
if "Failed to get value" in cutout_test:
continue
# get the cutout again as the other function also cleans it
cutout = get_cutout(rro_file)
if cutout is None:
continue
return rro_file
return None
prop_files = [
'/var/lib/lxc/android/rootfs/vendor/build.prop',
'/android/vendor/build.prop',
'/vendor/build.prop'
]
prop_file = None
for file in prop_files:
if os.path.exists(file):
prop_file = file
break
if prop_file is None:
print("no valid prop files found, exiting")
sys.exit(0)
manufacturer = extract_value_from_prop(prop_file, 'ro.product.vendor.manufacturer')
model = extract_value_from_prop(prop_file, 'ro.product.vendor.model')
apiver = extract_value_from_prop(prop_file, 'ro.vendor.build.version.sdk')
rro_file = find_apk_with_properties('/vendor/overlay')
if rro_file is None:
print("no valid files found, exiting")
sys.exit(0)
if rro_file and os.path.exists(rro_file):
radius = os.popen(f'getoverlay -p {rro_file} -c rounded_corner_radius_top').read().strip()
if "Failed to get value" not in radius:
radius = int(radius.rstrip('px').rstrip('dp'))
else:
radius = None
if os.path.exists(rro_file):
cutout = get_cutout(rro_file)
if cutout is not None:
cutout = reposition_svg(cutout, width)
if radius is None and cutout is None:
print("Device does not have a display cutout or a specified border radius.")
sys.exit(0)
json_obj = {
"name": f"{manufacturer} {model}",
"x-res": width,
"y-res": height
}
if radius is not None:
json_obj["border-radius"] = radius
if cutout is not None:
json_obj["cutouts"] = [{"name": "notch", "path": cutout}]
with open(args.output, 'w') as json_file:
json.dump(json_obj, json_file, indent=4)
else:
print(f"{rro_file} does not exist, exiting")
sys.exit(0)