1use crate::asset::AssetManager;
13use num_enum::{FromPrimitive, IntoPrimitive};
14use std::fmt;
15use std::ptr::NonNull;
16
17pub struct Configuration {
23 ptr: NonNull<ffi::AConfiguration>,
24}
25
26unsafe impl Send for Configuration {}
27unsafe impl Sync for Configuration {}
28
29impl Drop for Configuration {
30 fn drop(&mut self) {
31 unsafe { ffi::AConfiguration_delete(self.ptr.as_ptr()) }
32 }
33}
34
35impl Clone for Configuration {
36 fn clone(&self) -> Self {
37 let mut new = Self::new();
38 new.copy(self);
39 new
40 }
41}
42
43impl PartialEq for Configuration {
44 fn eq(&self, other: &Self) -> bool {
45 self.diff(other).0 == 0
46 }
47}
48impl Eq for Configuration {}
49
50impl fmt::Debug for Configuration {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 f.debug_struct("Configuration")
53 .field("mcc", &self.mcc())
54 .field("mnc", &self.mnc())
55 .field("lang", &self.language())
56 .field("country", &self.country())
57 .field("orientation", &self.orientation())
58 .field("touchscreen", &self.touchscreen())
59 .field("density", &self.density())
60 .field("keyboard", &self.keyboard())
61 .field("navigation", &self.navigation())
62 .field("keys_hidden", &self.keys_hidden())
63 .field("nav_hidden", &self.nav_hidden())
64 .field("sdk_version", &self.sdk_version())
65 .field("screen_size", &self.screen_size())
66 .field("screen_long", &self.screen_long())
67 .field("ui_mode_type", &self.ui_mode_type())
68 .field("ui_mode_night", &self.ui_mode_night())
69 .finish()
70 }
71}
72
73impl Configuration {
74 pub unsafe fn from_ptr(ptr: NonNull<ffi::AConfiguration>) -> Self {
80 Self { ptr }
81 }
82
83 pub unsafe fn clone_from_ptr(ptr: NonNull<ffi::AConfiguration>) -> Self {
92 let conf = Self::new();
93 ffi::AConfiguration_copy(conf.ptr.as_ptr(), ptr.as_ptr());
94 conf
95 }
96
97 pub fn ptr(&self) -> NonNull<ffi::AConfiguration> {
100 self.ptr
101 }
102
103 pub fn from_asset_manager(am: &AssetManager) -> Self {
104 let config = Self::new();
105 unsafe {
106 ffi::AConfiguration_fromAssetManager(config.ptr().as_mut(), am.ptr().as_mut());
107 }
108 config
109 }
110
111 pub fn new() -> Self {
113 unsafe {
114 Self {
115 ptr: NonNull::new(ffi::AConfiguration_new()).unwrap(),
116 }
117 }
118 }
119
120 pub fn copy(&mut self, other: &Self) {
122 unsafe { ffi::AConfiguration_copy(self.ptr.as_ptr(), other.ptr.as_ptr()) }
123 }
124
125 pub fn diff(&self, other: &Self) -> DiffResult {
127 unsafe {
128 DiffResult(ffi::AConfiguration_diff(self.ptr.as_ptr(), other.ptr.as_ptr()) as u32)
129 }
130 }
131
132 pub fn matches(&self, requested: &Self) -> bool {
134 unsafe { ffi::AConfiguration_match(self.ptr.as_ptr(), requested.ptr.as_ptr()) != 0 }
135 }
136
137 pub fn country(&self) -> Option<String> {
139 let mut chars = [0u8; 2];
140 unsafe {
141 ffi::AConfiguration_getCountry(self.ptr.as_ptr(), chars.as_mut_ptr().cast());
142 }
143 if chars[0] == 0 {
144 None
145 } else {
146 Some(std::str::from_utf8(chars.as_slice()).unwrap().to_owned())
147 }
148 }
149
150 pub fn density(&self) -> Option<u32> {
154 let density = unsafe { ffi::AConfiguration_getDensity(self.ptr.as_ptr()) as u32 };
155 match density {
156 ffi::ACONFIGURATION_DENSITY_DEFAULT => Some(160),
157 ffi::ACONFIGURATION_DENSITY_ANY => None,
158 ffi::ACONFIGURATION_DENSITY_NONE => None,
159 density => Some(density),
160 }
161 }
162
163 pub fn keyboard(&self) -> Keyboard {
165 unsafe { ffi::AConfiguration_getKeyboard(self.ptr.as_ptr()).into() }
166 }
167
168 pub fn keys_hidden(&self) -> KeysHidden {
170 unsafe { ffi::AConfiguration_getKeysHidden(self.ptr.as_ptr()).into() }
171 }
172
173 pub fn language(&self) -> Option<String> {
175 let mut chars = [0u8; 2];
176 unsafe {
177 ffi::AConfiguration_getLanguage(self.ptr.as_ptr(), chars.as_mut_ptr().cast());
178 }
179 if chars[0] == 0 {
180 None
181 } else {
182 Some(std::str::from_utf8(chars.as_slice()).unwrap().to_owned())
183 }
184 }
185
186 pub fn layout_direction(&self) -> LayoutDir {
188 unsafe { ffi::AConfiguration_getLayoutDirection(self.ptr.as_ptr()).into() }
189 }
190
191 pub fn mcc(&self) -> i32 {
193 unsafe { ffi::AConfiguration_getMcc(self.ptr.as_ptr()) }
194 }
195
196 pub fn mnc(&self) -> Option<i32> {
198 unsafe {
199 match ffi::AConfiguration_getMnc(self.ptr.as_ptr()) {
200 0 => None,
201 x if x == ffi::ACONFIGURATION_MNC_ZERO as i32 => Some(0),
202 x => Some(x),
203 }
204 }
205 }
206
207 pub fn nav_hidden(&self) -> NavHidden {
208 unsafe { ffi::AConfiguration_getNavHidden(self.ptr.as_ptr()).into() }
209 }
210
211 pub fn navigation(&self) -> Navigation {
212 unsafe { ffi::AConfiguration_getNavigation(self.ptr.as_ptr()).into() }
213 }
214
215 pub fn orientation(&self) -> Orientation {
216 unsafe { ffi::AConfiguration_getOrientation(self.ptr.as_ptr()).into() }
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 { ffi::AConfiguration_getScreenLong(self.ptr.as_ptr()).into() }
243 }
244
245 #[cfg(feature = "api-level-30")]
246 pub fn screen_round(&self) -> ScreenRound {
247 unsafe { ffi::AConfiguration_getScreenRound(self.ptr.as_ptr()).into() }
248 }
249
250 pub fn screen_size(&self) -> ScreenSize {
251 unsafe { ffi::AConfiguration_getScreenSize(self.ptr.as_ptr()).into() }
252 }
253
254 pub fn sdk_version(&self) -> i32 {
255 unsafe { ffi::AConfiguration_getSdkVersion(self.ptr.as_ptr()) }
256 }
257
258 pub fn smallest_screen_width_dp(&self) -> Option<i32> {
259 unsafe {
260 let width = ffi::AConfiguration_getSmallestScreenWidthDp(self.ptr.as_ptr());
261 if width == ffi::ACONFIGURATION_SMALLEST_SCREEN_WIDTH_DP_ANY as i32 {
262 None
263 } else {
264 Some(width)
265 }
266 }
267 }
268
269 pub fn touchscreen(&self) -> Touchscreen {
270 unsafe { ffi::AConfiguration_getTouchscreen(self.ptr.as_ptr()).into() }
271 }
272
273 pub fn ui_mode_night(&self) -> UiModeNight {
274 unsafe { ffi::AConfiguration_getUiModeNight(self.ptr.as_ptr()).into() }
275 }
276
277 pub fn ui_mode_type(&self) -> UiModeType {
278 unsafe { ffi::AConfiguration_getUiModeType(self.ptr.as_ptr()).into() }
279 }
280}
281
282#[derive(Copy, Clone, Debug, PartialEq, Eq)]
284pub struct DiffResult(pub u32);
285
286impl DiffResult {
287 pub fn mcc(self) -> bool {
288 self.0 & ffi::ACONFIGURATION_MCC != 0
289 }
290 pub fn mnc(self) -> bool {
291 self.0 & ffi::ACONFIGURATION_MNC != 0
292 }
293 pub fn locale(self) -> bool {
294 self.0 & ffi::ACONFIGURATION_LOCALE != 0
295 }
296 pub fn touchscreen(self) -> bool {
297 self.0 & ffi::ACONFIGURATION_TOUCHSCREEN != 0
298 }
299 pub fn keyboard(self) -> bool {
300 self.0 & ffi::ACONFIGURATION_KEYBOARD != 0
301 }
302 pub fn keyboard_hidden(self) -> bool {
303 self.0 & ffi::ACONFIGURATION_KEYBOARD_HIDDEN != 0
304 }
305 pub fn navigation(self) -> bool {
306 self.0 & ffi::ACONFIGURATION_NAVIGATION != 0
307 }
308 pub fn orientation(self) -> bool {
309 self.0 & ffi::ACONFIGURATION_ORIENTATION != 0
310 }
311 pub fn density(self) -> bool {
312 self.0 & ffi::ACONFIGURATION_DENSITY != 0
313 }
314 pub fn screen_size(self) -> bool {
315 self.0 & ffi::ACONFIGURATION_SCREEN_SIZE != 0
316 }
317 pub fn version(self) -> bool {
318 self.0 & ffi::ACONFIGURATION_VERSION != 0
319 }
320 pub fn screen_layout(self) -> bool {
321 self.0 & ffi::ACONFIGURATION_SCREEN_LAYOUT != 0
322 }
323 pub fn ui_mode(self) -> bool {
324 self.0 & ffi::ACONFIGURATION_UI_MODE != 0
325 }
326 pub fn smallest_screen_size(self) -> bool {
327 self.0 & ffi::ACONFIGURATION_SMALLEST_SCREEN_SIZE != 0
328 }
329 pub fn layout_dir(self) -> bool {
330 self.0 & ffi::ACONFIGURATION_LAYOUTDIR != 0
331 }
332 pub fn screen_round(self) -> bool {
333 self.0 & ffi::ACONFIGURATION_SCREEN_ROUND != 0
334 }
335 pub fn color_mode(self) -> bool {
336 self.0 & ffi::ACONFIGURATION_COLOR_MODE != 0
337 }
338}
339
340#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
341#[repr(i32)]
342#[non_exhaustive]
343pub enum Orientation {
344 Any = ffi::ACONFIGURATION_ORIENTATION_ANY as i32,
345 Port = ffi::ACONFIGURATION_ORIENTATION_PORT as i32,
346 Land = ffi::ACONFIGURATION_ORIENTATION_LAND as i32,
347 Square = ffi::ACONFIGURATION_ORIENTATION_SQUARE as i32,
348
349 #[doc(hidden)]
350 #[num_enum(catch_all)]
351 __Unknown(i32),
352}
353
354#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
355#[repr(i32)]
356#[non_exhaustive]
357pub enum Touchscreen {
358 Any = ffi::ACONFIGURATION_TOUCHSCREEN_ANY as i32,
359 NoTouch = ffi::ACONFIGURATION_TOUCHSCREEN_NOTOUCH as i32,
360 Stylus = ffi::ACONFIGURATION_TOUCHSCREEN_STYLUS as i32,
361 Finger = ffi::ACONFIGURATION_TOUCHSCREEN_FINGER as i32,
362
363 #[doc(hidden)]
364 #[num_enum(catch_all)]
365 __Unknown(i32),
366}
367
368#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
369#[repr(i32)]
370#[non_exhaustive]
371pub enum Density {
372 Default = ffi::ACONFIGURATION_DENSITY_DEFAULT as i32,
373 Low = ffi::ACONFIGURATION_DENSITY_LOW as i32,
374 Medium = ffi::ACONFIGURATION_DENSITY_MEDIUM as i32,
375 TV = ffi::ACONFIGURATION_DENSITY_TV as i32,
376 High = ffi::ACONFIGURATION_DENSITY_HIGH as i32,
377 XHigh = ffi::ACONFIGURATION_DENSITY_XHIGH as i32,
378 XXHigh = ffi::ACONFIGURATION_DENSITY_XXHIGH as i32,
379 XXXHigh = ffi::ACONFIGURATION_DENSITY_XXXHIGH as i32,
380 Any = ffi::ACONFIGURATION_DENSITY_ANY as i32,
381 None = ffi::ACONFIGURATION_DENSITY_NONE as i32,
382
383 #[doc(hidden)]
384 #[num_enum(catch_all)]
385 __Unknown(i32),
386}
387
388impl Density {
389 pub fn dpi(self) -> Option<u32> {
395 match self {
396 Self::Default => Some(160), Self::Low => Some(120),
398 Self::Medium => Some(160),
399 Self::High => Some(240),
400 Self::XHigh => Some(320),
401 Self::XXHigh => Some(480),
402 Self::XXXHigh => Some(640),
403 Self::TV => Some(213),
404 Self::Any => None,
405 Self::None => None,
406 Self::__Unknown(v) => Some(v as u32),
408 }
409 }
410
411 pub fn approx_hidpi_factor(self) -> Option<f64> {
419 match self {
420 Self::Default => Some(1.), Self::Low => Some(0.75),
422 Self::Medium => Some(1.),
423 Self::High => Some(1.5),
424 Self::XHigh => Some(2.),
425 Self::XXHigh => Some(3.),
426 Self::XXXHigh => Some(4.),
427 Self::TV => Some(4. / 3.),
428 Self::Any => None,
429 Self::None => None,
430 Self::__Unknown(_) => None,
431 }
432 }
433}
434
435#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
436#[repr(i32)]
437#[non_exhaustive]
438pub enum Keyboard {
439 Any = ffi::ACONFIGURATION_KEYBOARD_ANY as i32,
440 NoKeys = ffi::ACONFIGURATION_KEYBOARD_NOKEYS as i32,
441 Qwerty = ffi::ACONFIGURATION_KEYBOARD_QWERTY as i32,
442 TwelveKey = ffi::ACONFIGURATION_KEYBOARD_12KEY as i32,
443
444 #[doc(hidden)]
445 #[num_enum(catch_all)]
446 __Unknown(i32),
447}
448
449#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
450#[repr(i32)]
451#[non_exhaustive]
452pub enum Navigation {
453 Any = ffi::ACONFIGURATION_NAVIGATION_ANY as i32,
454 NoNav = ffi::ACONFIGURATION_NAVIGATION_NONAV as i32,
455 DPad = ffi::ACONFIGURATION_NAVIGATION_DPAD as i32,
456 Trackball = ffi::ACONFIGURATION_NAVIGATION_TRACKBALL as i32,
457 Wheel = ffi::ACONFIGURATION_NAVIGATION_WHEEL as i32,
458
459 #[doc(hidden)]
460 #[num_enum(catch_all)]
461 __Unknown(i32),
462}
463
464#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
465#[repr(i32)]
466#[non_exhaustive]
467pub enum KeysHidden {
468 Any = ffi::ACONFIGURATION_KEYSHIDDEN_ANY as i32,
469 No = ffi::ACONFIGURATION_KEYSHIDDEN_NO as i32,
470 Yes = ffi::ACONFIGURATION_KEYSHIDDEN_YES as i32,
471 Soft = ffi::ACONFIGURATION_KEYSHIDDEN_SOFT as i32,
472
473 #[doc(hidden)]
474 #[num_enum(catch_all)]
475 __Unknown(i32),
476}
477
478#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
479#[repr(i32)]
480#[non_exhaustive]
481pub enum NavHidden {
482 Any = ffi::ACONFIGURATION_NAVHIDDEN_ANY as i32,
483 No = ffi::ACONFIGURATION_NAVHIDDEN_NO as i32,
484 Yes = ffi::ACONFIGURATION_NAVHIDDEN_YES as i32,
485
486 #[doc(hidden)]
487 #[num_enum(catch_all)]
488 __Unknown(i32),
489}
490
491#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
492#[repr(i32)]
493#[non_exhaustive]
494pub enum ScreenSize {
495 Any = ffi::ACONFIGURATION_SCREENSIZE_ANY as i32,
496 Small = ffi::ACONFIGURATION_SCREENSIZE_SMALL as i32,
497 Normal = ffi::ACONFIGURATION_SCREENSIZE_NORMAL as i32,
498 Large = ffi::ACONFIGURATION_SCREENSIZE_LARGE as i32,
499 XLarge = ffi::ACONFIGURATION_SCREENSIZE_XLARGE as i32,
500
501 #[doc(hidden)]
502 #[num_enum(catch_all)]
503 __Unknown(i32),
504}
505
506#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
507#[repr(i32)]
508#[non_exhaustive]
509pub enum ScreenLong {
510 Any = ffi::ACONFIGURATION_SCREENLONG_ANY as i32,
511 No = ffi::ACONFIGURATION_SCREENLONG_NO as i32,
512 Yes = ffi::ACONFIGURATION_SCREENLONG_YES as i32,
513
514 #[doc(hidden)]
515 #[num_enum(catch_all)]
516 __Unknown(i32),
517}
518
519#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
520#[repr(i32)]
521#[non_exhaustive]
522pub enum ScreenRound {
523 Any = ffi::ACONFIGURATION_SCREENROUND_ANY as i32,
524 No = ffi::ACONFIGURATION_SCREENROUND_NO as i32,
525 Yes = ffi::ACONFIGURATION_SCREENROUND_YES as i32,
526
527 #[doc(hidden)]
528 #[num_enum(catch_all)]
529 __Unknown(i32),
530}
531
532#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
533#[repr(i32)]
534#[non_exhaustive]
535pub enum WideColorGamut {
536 Any = ffi::ACONFIGURATION_WIDE_COLOR_GAMUT_ANY as i32,
537 No = ffi::ACONFIGURATION_WIDE_COLOR_GAMUT_NO as i32,
538 Yes = ffi::ACONFIGURATION_WIDE_COLOR_GAMUT_YES as i32,
539
540 #[doc(hidden)]
541 #[num_enum(catch_all)]
542 __Unknown(i32),
543}
544
545#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
546#[repr(i32)]
547#[non_exhaustive]
548pub enum HDR {
549 Any = ffi::ACONFIGURATION_HDR_ANY as i32,
550 No = ffi::ACONFIGURATION_HDR_NO as i32,
551 Yes = ffi::ACONFIGURATION_HDR_YES as i32,
552
553 #[doc(hidden)]
554 #[num_enum(catch_all)]
555 __Unknown(i32),
556}
557
558#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
559#[repr(i32)]
560#[non_exhaustive]
561pub enum LayoutDir {
562 Any = ffi::ACONFIGURATION_LAYOUTDIR_ANY as i32,
563 Ltr = ffi::ACONFIGURATION_LAYOUTDIR_LTR as i32,
564 Rtl = ffi::ACONFIGURATION_LAYOUTDIR_RTL as i32,
565
566 #[doc(hidden)]
567 #[num_enum(catch_all)]
568 __Unknown(i32),
569}
570
571#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
572#[repr(i32)]
573#[non_exhaustive]
574pub enum UiModeType {
575 Any = ffi::ACONFIGURATION_UI_MODE_TYPE_ANY as i32,
576 Normal = ffi::ACONFIGURATION_UI_MODE_TYPE_NORMAL as i32,
577 Desk = ffi::ACONFIGURATION_UI_MODE_TYPE_DESK as i32,
578 Car = ffi::ACONFIGURATION_UI_MODE_TYPE_CAR as i32,
579 Television = ffi::ACONFIGURATION_UI_MODE_TYPE_TELEVISION as i32,
580 Applicance = ffi::ACONFIGURATION_UI_MODE_TYPE_APPLIANCE as i32,
581 Watch = ffi::ACONFIGURATION_UI_MODE_TYPE_WATCH as i32,
582 VrHeadset = ffi::ACONFIGURATION_UI_MODE_TYPE_VR_HEADSET as i32,
583
584 #[doc(hidden)]
585 #[num_enum(catch_all)]
586 __Unknown(i32),
587}
588
589#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
590#[repr(i32)]
591#[non_exhaustive]
592pub enum UiModeNight {
593 Any = ffi::ACONFIGURATION_UI_MODE_NIGHT_ANY as i32,
594 No = ffi::ACONFIGURATION_UI_MODE_NIGHT_NO as i32,
595 Yes = ffi::ACONFIGURATION_UI_MODE_NIGHT_YES as i32,
596
597 #[doc(hidden)]
598 #[num_enum(catch_all)]
599 __Unknown(i32),
600}