1use num_enum::{IntoPrimitive, TryFromPrimitive};
11use std::convert::TryInto;
12use std::fmt;
13use std::ptr::NonNull;
14
15pub struct Configuration {
20 ptr: NonNull<ffi::AConfiguration>,
21}
22
23unsafe impl Send for Configuration {}
24unsafe impl Sync for Configuration {}
25
26impl Drop for Configuration {
27 fn drop(&mut self) {
28 unsafe { ffi::AConfiguration_delete(self.ptr.as_ptr()) }
29 }
30}
31
32impl Clone for Configuration {
33 fn clone(&self) -> Self {
34 let mut new = Self::new();
35 new.copy(self);
36 new
37 }
38}
39
40impl PartialEq for Configuration {
41 fn eq(&self, other: &Self) -> bool {
42 self.diff(other).0 == 0
43 }
44}
45impl Eq for Configuration {}
46
47impl fmt::Debug for Configuration {
48 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
49 f.debug_struct("Configuration")
50 .field("mcc", &self.mcc())
51 .field("mnc", &self.mnc())
52 .field("lang", &self.language())
53 .field("country", &self.country())
54 .field("orientation", &self.orientation())
55 .field("touchscreen", &self.touchscreen())
56 .field("density", &self.density())
57 .field("keyboard", &self.keyboard())
58 .field("navigation", &self.navigation())
59 .field("keys_hidden", &self.keys_hidden())
60 .field("nav_hidden", &self.nav_hidden())
61 .field("sdk_version", &self.sdk_version())
62 .field("screen_size", &self.screen_size())
63 .field("screen_long", &self.screen_long())
64 .field("ui_mode_type", &self.ui_mode_type())
65 .field("ui_mode_night", &self.ui_mode_night())
66 .finish()
67 }
68}
69
70impl Configuration {
71 pub unsafe fn from_ptr(ptr: NonNull<ffi::AConfiguration>) -> Self {
76 Self { ptr }
77 }
78
79 pub unsafe fn clone_from_ptr(ptr: NonNull<ffi::AConfiguration>) -> Self {
84 let conf = Self::new();
85 ffi::AConfiguration_copy(conf.ptr.as_ptr(), ptr.as_ptr());
86 conf
87 }
88
89 pub fn ptr(&self) -> NonNull<ffi::AConfiguration> {
92 self.ptr
93 }
94
95 pub fn new() -> Self {
97 unsafe {
98 Self {
99 ptr: NonNull::new(ffi::AConfiguration_new()).unwrap(),
100 }
101 }
102 }
103
104 pub fn copy(&mut self, other: &Self) {
106 unsafe { ffi::AConfiguration_copy(self.ptr.as_ptr(), other.ptr.as_ptr()) }
107 }
108
109 pub fn diff(&self, other: &Self) -> DiffResult {
111 unsafe {
112 DiffResult(ffi::AConfiguration_diff(self.ptr.as_ptr(), other.ptr.as_ptr()) as u32)
113 }
114 }
115
116 pub fn matches(&self, requested: &Self) -> bool {
118 unsafe { ffi::AConfiguration_match(self.ptr.as_ptr(), requested.ptr.as_ptr()) != 0 }
119 }
120
121 pub fn country(&self) -> String {
123 let mut result = " ".to_owned();
124 unsafe {
125 ffi::AConfiguration_getCountry(self.ptr.as_ptr(), result.as_mut_ptr() as *mut _);
126 }
127 result
128 }
129
130 pub fn density(&self) -> Density {
132 unsafe {
133 (ffi::AConfiguration_getDensity(self.ptr.as_ptr()) as u32)
134 .try_into()
135 .unwrap()
136 }
137 }
138
139 pub fn keyboard(&self) -> Keyboard {
141 unsafe {
142 (ffi::AConfiguration_getKeyboard(self.ptr.as_ptr()) as u32)
143 .try_into()
144 .unwrap()
145 }
146 }
147
148 pub fn keys_hidden(&self) -> KeysHidden {
150 unsafe {
151 (ffi::AConfiguration_getKeysHidden(self.ptr.as_ptr()) as u32)
152 .try_into()
153 .unwrap()
154 }
155 }
156
157 pub fn language(&self) -> Option<String> {
159 let mut chars = [0u8; 2];
160 unsafe {
161 ffi::AConfiguration_getLanguage(self.ptr.as_ptr(), chars[..].as_mut_ptr() as *mut _);
162 }
163 if chars[0] == 0 {
164 None
165 } else {
166 Some(std::str::from_utf8(&chars[..]).unwrap().to_owned())
167 }
168 }
169
170 pub fn layout_direction(&self) -> LayoutDir {
172 unsafe {
173 (ffi::AConfiguration_getLayoutDirection(self.ptr.as_ptr()) as u32)
174 .try_into()
175 .unwrap()
176 }
177 }
178
179 pub fn mcc(&self) -> i32 {
181 unsafe { ffi::AConfiguration_getMcc(self.ptr.as_ptr()) }
182 }
183
184 pub fn mnc(&self) -> Option<i32> {
186 unsafe {
187 match ffi::AConfiguration_getMnc(self.ptr.as_ptr()) {
188 0 => None,
189 x if x == ffi::ACONFIGURATION_MNC_ZERO as i32 => Some(0),
190 x => Some(x),
191 }
192 }
193 }
194
195 pub fn nav_hidden(&self) -> NavHidden {
196 unsafe {
197 (ffi::AConfiguration_getNavHidden(self.ptr.as_ptr()) as u32)
198 .try_into()
199 .unwrap()
200 }
201 }
202
203 pub fn navigation(&self) -> Navigation {
204 unsafe {
205 (ffi::AConfiguration_getNavigation(self.ptr.as_ptr()) as u32)
206 .try_into()
207 .unwrap()
208 }
209 }
210
211 pub fn orientation(&self) -> Orientation {
212 unsafe {
213 (ffi::AConfiguration_getOrientation(self.ptr.as_ptr()) as u32)
214 .try_into()
215 .unwrap()
216 }
217 }
218
219 pub fn screen_height_dp(&self) -> Option<i32> {
220 unsafe {
221 let height = ffi::AConfiguration_getScreenHeightDp(self.ptr.as_ptr());
222 if height == ffi::ACONFIGURATION_SCREEN_HEIGHT_DP_ANY as i32 {
223 None
224 } else {
225 Some(height)
226 }
227 }
228 }
229
230 pub fn screen_width_dp(&self) -> Option<i32> {
231 unsafe {
232 let width = ffi::AConfiguration_getScreenWidthDp(self.ptr.as_ptr());
233 if width == ffi::ACONFIGURATION_SCREEN_WIDTH_DP_ANY as i32 {
234 None
235 } else {
236 Some(width)
237 }
238 }
239 }
240
241 pub fn screen_long(&self) -> ScreenLong {
242 unsafe {
243 (ffi::AConfiguration_getScreenLong(self.ptr.as_ptr()) as u32)
244 .try_into()
245 .unwrap()
246 }
247 }
248
249 pub fn screen_round(&self) -> ScreenRound {
250 unsafe {
251 (ffi::AConfiguration_getScreenRound(self.ptr.as_ptr()) as u32)
252 .try_into()
253 .unwrap()
254 }
255 }
256
257 pub fn screen_size(&self) -> ScreenSize {
258 unsafe {
259 (ffi::AConfiguration_getScreenSize(self.ptr.as_ptr()) as u32)
260 .try_into()
261 .unwrap()
262 }
263 }
264
265 pub fn sdk_version(&self) -> i32 {
266 unsafe { ffi::AConfiguration_getSdkVersion(self.ptr.as_ptr()) }
267 }
268
269 pub fn smallest_screen_width_dp(&self) -> Option<i32> {
270 unsafe {
271 let width = ffi::AConfiguration_getSmallestScreenWidthDp(self.ptr.as_ptr());
272 if width == ffi::ACONFIGURATION_SMALLEST_SCREEN_WIDTH_DP_ANY as i32 {
273 None
274 } else {
275 Some(width)
276 }
277 }
278 }
279
280 pub fn touchscreen(&self) -> Touchscreen {
281 unsafe {
282 (ffi::AConfiguration_getTouchscreen(self.ptr.as_ptr()) as u32)
283 .try_into()
284 .unwrap()
285 }
286 }
287
288 pub fn ui_mode_night(&self) -> UiModeNight {
289 unsafe {
290 (ffi::AConfiguration_getUiModeNight(self.ptr.as_ptr()) as u32)
291 .try_into()
292 .unwrap()
293 }
294 }
295
296 pub fn ui_mode_type(&self) -> UiModeType {
297 unsafe {
298 (ffi::AConfiguration_getUiModeType(self.ptr.as_ptr()) as u32)
299 .try_into()
300 .unwrap()
301 }
302 }
303}
304
305#[derive(Copy, Clone, Debug, PartialEq, Eq)]
307pub struct DiffResult(pub u32);
308
309impl DiffResult {
310 pub fn mcc(self) -> bool {
311 self.0 & ffi::ACONFIGURATION_MCC != 0
312 }
313 pub fn mnc(self) -> bool {
314 self.0 & ffi::ACONFIGURATION_MNC != 0
315 }
316 pub fn locale(self) -> bool {
317 self.0 & ffi::ACONFIGURATION_LOCALE != 0
318 }
319 pub fn touchscreen(self) -> bool {
320 self.0 & ffi::ACONFIGURATION_TOUCHSCREEN != 0
321 }
322 pub fn keyboard(self) -> bool {
323 self.0 & ffi::ACONFIGURATION_KEYBOARD != 0
324 }
325 pub fn keyboard_hidden(self) -> bool {
326 self.0 & ffi::ACONFIGURATION_KEYBOARD_HIDDEN != 0
327 }
328 pub fn navigation(self) -> bool {
329 self.0 & ffi::ACONFIGURATION_NAVIGATION != 0
330 }
331 pub fn orientation(self) -> bool {
332 self.0 & ffi::ACONFIGURATION_ORIENTATION != 0
333 }
334 pub fn density(self) -> bool {
335 self.0 & ffi::ACONFIGURATION_DENSITY != 0
336 }
337 pub fn screen_size(self) -> bool {
338 self.0 & ffi::ACONFIGURATION_SCREEN_SIZE != 0
339 }
340 pub fn version(self) -> bool {
341 self.0 & ffi::ACONFIGURATION_VERSION != 0
342 }
343 pub fn screen_layout(self) -> bool {
344 self.0 & ffi::ACONFIGURATION_SCREEN_LAYOUT != 0
345 }
346 pub fn ui_mode(self) -> bool {
347 self.0 & ffi::ACONFIGURATION_UI_MODE != 0
348 }
349 pub fn smallest_screen_size(self) -> bool {
350 self.0 & ffi::ACONFIGURATION_SMALLEST_SCREEN_SIZE != 0
351 }
352 pub fn layout_dir(self) -> bool {
353 self.0 & ffi::ACONFIGURATION_LAYOUTDIR != 0
354 }
355 pub fn screen_round(self) -> bool {
356 self.0 & ffi::ACONFIGURATION_SCREEN_ROUND != 0
357 }
358 pub fn color_mode(self) -> bool {
359 self.0 & ffi::ACONFIGURATION_COLOR_MODE != 0
360 }
361}
362
363#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
364#[repr(u32)]
365pub enum Orientation {
366 Any = ffi::ACONFIGURATION_ORIENTATION_ANY,
367 Port = ffi::ACONFIGURATION_ORIENTATION_PORT,
368 Land = ffi::ACONFIGURATION_ORIENTATION_LAND,
369 Square = ffi::ACONFIGURATION_ORIENTATION_SQUARE,
370}
371
372#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
373#[repr(u32)]
374pub enum Touchscreen {
375 Any = ffi::ACONFIGURATION_TOUCHSCREEN_ANY,
376 NoTouch = ffi::ACONFIGURATION_TOUCHSCREEN_NOTOUCH,
377 Stylus = ffi::ACONFIGURATION_TOUCHSCREEN_STYLUS,
378 Finger = ffi::ACONFIGURATION_TOUCHSCREEN_FINGER,
379}
380
381#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
382#[repr(u32)]
383pub enum Density {
384 Default = ffi::ACONFIGURATION_DENSITY_DEFAULT,
385 Low = ffi::ACONFIGURATION_DENSITY_LOW,
386 Medium = ffi::ACONFIGURATION_DENSITY_MEDIUM,
387 TV = ffi::ACONFIGURATION_DENSITY_TV,
388 High = ffi::ACONFIGURATION_DENSITY_HIGH,
389 XHigh = ffi::ACONFIGURATION_DENSITY_XHIGH,
390 XXHigh = ffi::ACONFIGURATION_DENSITY_XXHIGH,
391 XXXHigh = ffi::ACONFIGURATION_DENSITY_XXXHIGH,
392 Any = ffi::ACONFIGURATION_DENSITY_ANY,
393 None = ffi::ACONFIGURATION_DENSITY_NONE,
394}
395
396impl Density {
397 pub fn approx_dpi(self) -> Option<u32> {
403 match self {
404 Self::Default => Some(160), Self::Low => Some(120),
406 Self::Medium => Some(160),
407 Self::High => Some(240),
408 Self::XHigh => Some(320),
409 Self::XXHigh => Some(480),
410 Self::XXXHigh => Some(640),
411 Self::TV => Some(213),
412 Self::Any => None,
413 Self::None => None,
414 }
415 }
416
417 pub fn approx_hidpi_factor(self) -> Option<f64> {
425 match self {
426 Self::Default => Some(1.), Self::Low => Some(0.75),
428 Self::Medium => Some(1.),
429 Self::High => Some(1.5),
430 Self::XHigh => Some(2.),
431 Self::XXHigh => Some(3.),
432 Self::XXXHigh => Some(4.),
433 Self::TV => Some(4. / 3.),
434 Self::Any => None,
435 Self::None => None,
436 }
437 }
438}
439
440#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
441#[repr(u32)]
442pub enum Keyboard {
443 Any = ffi::ACONFIGURATION_KEYBOARD_ANY,
444 NoKeys = ffi::ACONFIGURATION_KEYBOARD_NOKEYS,
445 Qwerty = ffi::ACONFIGURATION_KEYBOARD_QWERTY,
446 TwelveKey = ffi::ACONFIGURATION_KEYBOARD_12KEY,
447}
448
449#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
452#[repr(u32)]
453pub enum Navigation {
454 Any = ffi::ACONFIGURATION_NAVIGATION_ANY,
455 NoNav = ffi::ACONFIGURATION_NAVIGATION_NONAV,
456 DPad = ffi::ACONFIGURATION_NAVIGATION_DPAD,
457 Trackball = ffi::ACONFIGURATION_NAVIGATION_TRACKBALL,
458 Wheel = ffi::ACONFIGURATION_NAVIGATION_WHEEL,
459}
460
461#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
462#[repr(u32)]
463pub enum KeysHidden {
464 Any = ffi::ACONFIGURATION_KEYSHIDDEN_ANY,
465 No = ffi::ACONFIGURATION_KEYSHIDDEN_NO,
466 Yes = ffi::ACONFIGURATION_KEYSHIDDEN_YES,
467 Soft = ffi::ACONFIGURATION_KEYSHIDDEN_SOFT,
468}
469
470#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
471#[repr(u32)]
472pub enum NavHidden {
473 Any = ffi::ACONFIGURATION_NAVHIDDEN_ANY,
474 No = ffi::ACONFIGURATION_NAVHIDDEN_NO,
475 Yes = ffi::ACONFIGURATION_NAVHIDDEN_YES,
476}
477
478#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
479#[repr(u32)]
480pub enum ScreenSize {
481 Any = ffi::ACONFIGURATION_SCREENSIZE_ANY,
482 Small = ffi::ACONFIGURATION_SCREENSIZE_SMALL,
483 Normal = ffi::ACONFIGURATION_SCREENSIZE_NORMAL,
484 Large = ffi::ACONFIGURATION_SCREENSIZE_LARGE,
485 XLarge = ffi::ACONFIGURATION_SCREENSIZE_XLARGE,
486}
487
488#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
489#[repr(u32)]
490pub enum ScreenLong {
491 Any = ffi::ACONFIGURATION_SCREENLONG_ANY,
492 No = ffi::ACONFIGURATION_SCREENLONG_NO,
493 Yes = ffi::ACONFIGURATION_SCREENLONG_YES,
494}
495
496#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
497#[repr(u32)]
498pub enum ScreenRound {
499 Any = ffi::ACONFIGURATION_SCREENROUND_ANY,
500 No = ffi::ACONFIGURATION_SCREENROUND_NO,
501 Yes = ffi::ACONFIGURATION_SCREENROUND_YES,
502}
503
504#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
505#[repr(u32)]
506pub enum WideColorGamut {
507 Any = ffi::ACONFIGURATION_WIDE_COLOR_GAMUT_ANY,
508 No = ffi::ACONFIGURATION_WIDE_COLOR_GAMUT_NO,
509 Yes = ffi::ACONFIGURATION_WIDE_COLOR_GAMUT_YES,
510}
511
512#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
513#[repr(u32)]
514pub enum HDR {
515 Any = ffi::ACONFIGURATION_HDR_ANY,
516 No = ffi::ACONFIGURATION_HDR_NO,
517 Yes = ffi::ACONFIGURATION_HDR_YES,
518}
519
520#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
521#[repr(u32)]
522pub enum LayoutDir {
523 Any = ffi::ACONFIGURATION_LAYOUTDIR_ANY,
524 Ltr = ffi::ACONFIGURATION_LAYOUTDIR_LTR,
525 Rtl = ffi::ACONFIGURATION_LAYOUTDIR_RTL,
526}
527
528#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
529#[repr(u32)]
530pub enum UiModeType {
531 Any = ffi::ACONFIGURATION_UI_MODE_TYPE_ANY,
532 Normal = ffi::ACONFIGURATION_UI_MODE_TYPE_NORMAL,
533 Desk = ffi::ACONFIGURATION_UI_MODE_TYPE_DESK,
534 Car = ffi::ACONFIGURATION_UI_MODE_TYPE_CAR,
535 Television = ffi::ACONFIGURATION_UI_MODE_TYPE_TELEVISION,
536 Applicance = ffi::ACONFIGURATION_UI_MODE_TYPE_APPLIANCE,
537 Watch = ffi::ACONFIGURATION_UI_MODE_TYPE_WATCH,
538 VrHeadset = ffi::ACONFIGURATION_UI_MODE_TYPE_VR_HEADSET,
539}
540
541#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
542#[repr(u32)]
543pub enum UiModeNight {
544 Any = ffi::ACONFIGURATION_UI_MODE_NIGHT_ANY,
545 No = ffi::ACONFIGURATION_UI_MODE_NIGHT_NO,
546 Yes = ffi::ACONFIGURATION_UI_MODE_NIGHT_YES,
547}