Returns inconsistent values from Forms and Essentials.
Xamarin.Forms.Device.Idiom and Xamarin.Essentials.DeviceInfo.Idiom behave in same way.
Xamarin.Forms.Device.Idiom returns TargetIdiom.Desktop
Xamarin.Essentials.DeviceInfo.Idiom returns DeviceIdiom.Phone
XF 4.7
XF 4.4
It's a similar issue to https://github.com/xamarin/Essentials/issues/1027
Great! Another Xiaomi device and another results... This destroys my app completely :(
Xamarin.Froms.Device.Idiom == "Desktop"
Xamarin.Essentials.DeviceInfo.Idiom == "Phone"
Code used to render page:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reactive.Linq;
using Xamarin.Forms;
namespace Pages
{
public partial class DiagnosticPage : ContentPage
{
public List<string> List = new List<string>();
public DiagnosticPage()
{
this.List.Add($"XF.Device.Info.CurrentOrientation: {Device.Info.CurrentOrientation}");
this.List.Add($"XF.Device.Info.ScalingFactor: {Device.Info.ScalingFactor}");
this.List.Add($"XF.Device.Info.PixelScreenSize: {Device.Info.PixelScreenSize}");
this.List.Add($"XF.Device.Info.ScaledScreenSize: {Device.Info.ScaledScreenSize}");
this.List.Add($"XF.Device.Idiom: {Device.Idiom}");
this.List.Add($"XF.Device.RuntimePlatform: {Device.RuntimePlatform}");
this.List.Add($"Essentials.DeviceInfo.Idiom: {Xamarin.Essentials.DeviceInfo.Idiom}");
this.List.Add($"Essentials.DeviceInfo.Manufacturer: {Xamarin.Essentials.DeviceInfo.Manufacturer}");
this.List.Add($"Essentials.DeviceInfo.Model: {Xamarin.Essentials.DeviceInfo.Model}");
this.List.Add($"Essentials.DeviceInfo.Name: {Xamarin.Essentials.DeviceInfo.Name}");
this.List.Add($"Essentials.DeviceInfo.Platform: {Xamarin.Essentials.DeviceInfo.Platform}");
this.List.Add($"Essentials.DeviceInfo.Version: {Xamarin.Essentials.DeviceInfo.Version}");
this.List.Add($"Essentials.DeviceInfo.DeviceType: {Xamarin.Essentials.DeviceInfo.DeviceType}");
this.List.Add($"Essentials.DeviceInfo.VersionString: {Xamarin.Essentials.DeviceInfo.VersionString}");
this.InitializeComponent();
BindableLayout.SetItemsSource(this.Layout, this.List);
}
}
}
@@ -0,0 +1,17 @@
<ContentPage x:Class="Pages.DiagnosticPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
BackgroundColor="Black">
<Grid AutomationId="LoadingPageId" CompressedLayout.IsHeadless="True" BackgroundColor="Black">
<StackLayout x:Name="Layout">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label Text="{Binding .}" TextColor="White"/>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</Grid>
</ContentPage>
Can you fix this in Xamarin Forms 4.5?
Does it only occur for Xaomi devices?
Interesting, I suffer from the same issue, it was working just fine on Xamarin Forms 4.4.0.991640, and when we updated to 4.6.0.800 that happened.
Here's the list of affected devices by this bug on my side
and it's weird that it only affects some specific devices, like a user X with a Redmi Note 8 returns the Phone value while the user Y with a Redmi Note 8 returns a value that's not the one defined on the Phone idiom.
Sadly for me, because it's returning a non defined value it's crashing my app, here's an attached list showing that for some users the app is working just fine (receiving the Phone value) while others crash the app (by not receiving a Phone value)
Sadly, we have a Redmi Note 8 and a MI 8 Lite and both are returning the correct Phone values
@jsuarezruiz, Can you speed up the merge of your fixes? This bug causes a lot of crashes in my recently released project.
Devices where bug occurs, just for now more than 1 thousand crashes, and rising (2 days old app) :/
Application is bricked completely on those devices as we use Device.Idom in our core sdk.
Xiaomi Redmi Note 8 Pro
Xiaomi Redmi Note 4
Xiaomi Redmi Note 8T
Xiaomi Redmi Note 7
Xiaomi Redmi 6
Xiaomi Redmi Note 6 Pro
Xiaomi Redmi Note 5
Xiaomi Redmi 4A
Xiaomi MI 8
Xiaomi Redmi Note 8
Xiaomi Redmi 7
Xiaomi Redmi 5 Plus
rockchip X96 plus 4s.01.d4
Xiaomi Redmi 7A
Xiaomi POCOPHONE F1
Xiaomi Mi Note 10 Lite
Xiaomi Mi Note 10
Xiaomi Redmi 8
Xiaomi MI 8 Lite
Xiaomi Redmi Note 9 Pro
Xiaomi M2003J15SC
Xiaomi Redmi 8A
Xiaomi Mi MIX 2S
rockchip MXR PRO
Xiaomi Redmi Note 9S
Xiaomi Redmi 5
Xiaomi Mi 9 Lite
Xiaomi Redmi 4X
Xiaomi Redmi S2
rockchip MX10.o.00.d4
Xiaomi MI MAX 3
rockchip MBOX
rockchip MX10.11.p2.0.00.d4
rockchip H96Max RK3318
Xiaomi Redmi Note 5A Prime
Xiaomi Mi MIX 2
rockchip N5NOVA
Xiaomi Redmi Note 3
rockchip MiniA5X_Plus.hxj.p2.0.00.d4
rockchip H96 Max RK3318
Xiaomi Mi 9T Pro
rockchip A5X MAX00
rockchip X96 plus 4s.00.d4
rockchip MX9
Xiaomi Redmi 4
Xiaomi Redmi 5A
Xiaomi MI MAX
Xiaomi MI 5s
rockchip V4.SY.01.d4
Xiaomi MI MAX 2
Xiaomi Redmi 6 Pro
Xiaomi MI 9
Xiaomi Mi 9T
rockchip X88MAX.p2.0.01.d4
Workaround: Set the Default value for OnIdiom
For now i found solution to override OnIdiom for every occurence in my code...
public class OnIdiomOverride<T>
{
T _phone;
T _tablet;
T _desktop;
T _tV;
T _watch;
T _default;
bool _isPhoneSet;
bool _isTabletSet;
bool _isDesktopSet;
bool _isTVSet;
bool _isWatchSet;
bool _isDefaultSet;
public T Phone
{
get => _phone;
set
{
_phone = value;
_isPhoneSet = true;
}
}
public T Tablet
{
get => _tablet;
set
{
_tablet = value;
_isTabletSet = true;
}
}
public T Desktop
{
get => _desktop;
set
{
_desktop = value;
_isDesktopSet = true;
}
}
public T TV
{
get => _tV;
set
{
_tV = value;
_isTVSet = true;
}
}
public T Watch
{
get => _watch;
set
{
_watch = value;
_isWatchSet = true;
}
}
public T Default
{
get => _default;
set
{
_default = value;
_isDefaultSet = true;
}
}
public static implicit operator T(OnIdiomOverride<T> onIdiom)
{
// LOOK AT Xamarin.Essentials.DeviceInfo, because Xamarin.Forms.Device.Idiom is buggy
if (DeviceInfo.Idiom == DeviceIdiom.Phone)
{
return onIdiom._isPhoneSet ? onIdiom.Phone : (onIdiom._isDefaultSet ? onIdiom.Default : default(T));
}
if (DeviceInfo.Idiom == DeviceIdiom.Tablet)
{
return onIdiom._isTabletSet ? onIdiom.Tablet : (onIdiom._isDefaultSet ? onIdiom.Default : default(T));
}
if (DeviceInfo.Idiom == DeviceIdiom.Desktop)
{
return onIdiom._isDesktopSet ? onIdiom.Desktop : (onIdiom._isDefaultSet ? onIdiom.Default : default(T));
}
if (DeviceInfo.Idiom == DeviceIdiom.TV)
{
return onIdiom._isTVSet ? onIdiom.TV : (onIdiom._isDefaultSet ? onIdiom.Default : default(T));
}
if (DeviceInfo.Idiom == DeviceIdiom.Watch)
{
return onIdiom._isWatchSet ? onIdiom.Watch : (onIdiom._isDefaultSet ? onIdiom.Default : default(T));
}
return default;
}
}
And use this like that:
<xaml
xmlns:infrastructure="clr-namespace:hot-fix.Infrastructure;assembly=hotfix">
<Grid.IsVisible>
<infrastructure:OnIdiomOverride
x:TypeArguments="x:Boolean"
Phone="True"
Tablet="False" />
</Grid.IsVisible>
Its lame but for me its working, On c# usage is like this:
if (Application.Current.Resources.TryGetValue(maxItemsPerRowKey, out var maxItemsPerRowObject) && maxItemsPerRowObject is Hot.Fix.Namespace.OnIdiomOverride<int> maxItemsPerRowOnIdiom)
{
maxItemsPerRow = (int)maxItemsPerRowOnIdiom;
}
@lucas-zimerman
That would work, but my app would still crash as DeviceIdom is sometimes Uknown, Watch or Destkop. And my SDK would simply do other things that it supposed to do. Best way is to override OnIdom, so devices can use Xamarin.Essentials implementation
@samhouts i think i found problem. here you are cheking for https://github.com/xamarin/Xamarin.Forms/blob/719fc7a604ff0cce8922d717c99bfb0fa17e35e0/Xamarin.Forms.Platform.Android/Forms.cs#L399-L414 with .HasFlag() method on enum that definietly should return just single value. this: https://developer.android.com/reference/android/app/UiModeManager#getCurrentModeType() isn't flagable.
Essentials do right thing. Forms don't.
https://github.com/xamarin/Essentials/blob/3ab48b96240e7844a4abd68d5801b181151dc796/Xamarin.Essentials/DeviceInfo/DeviceInfo.android.cs#L73-L85
EDIT: I've just saw that you have opened PR that fixes this. Its a over month and still not merged ... :(
Bump, do you plan to merge this PR?
I'm just leaving this issue that ideally sums, that you don't care about community bugs as much as you could care. https://github.com/dotnet/maui/issues/109
i found cleaner workaround for this issue. Simply set Device.Idiom property via reflection on app start
public static class FixXamarin
{
public static void FixDevice()
{
var map = new Dictionary<DeviceIdiom, TargetIdiom>()
{
[DeviceIdiom.Desktop] = TargetIdiom.Desktop,
[DeviceIdiom.Phone] = TargetIdiom.Phone,
[DeviceIdiom.Tablet] = TargetIdiom.Tablet,
[DeviceIdiom.Unknown] = TargetIdiom.Unsupported,
[DeviceIdiom.Watch] = TargetIdiom.Watch,
[DeviceIdiom.TV] = TargetIdiom.TV,
};
var deviceIdiomProperty = typeof(Device).GetProperty("Idiom", BindingFlags.Public | BindingFlags.Static);
var mappedIdiom = map[Xamarin.Essentials.DeviceInfo.Idiom];
deviceIdiomProperty?.SetValue(null, mappedIdiom);
}
}
protected override void OnCreate(Bundle bundle)
{
FixXamarin.FixDevice(); // before init if forms using Incorrect values from Device.Idiom
Forms.Init(this, bundle);
FixXamarin.FixDevice(); // and after init for extra safety if Forms reseted value Device.Idiom
}
Most helpful comment
i found cleaner workaround for this issue. Simply set Device.Idiom property via reflection on app start