Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Commit e5604ee

Browse files
authored
Fix Resource Manager code to use native APIs before reflection (#13176)
* Fix Resource Manager code to use native APIs before reflection * - fix test for LR Renderers * Update ButtonTests.cs
1 parent 193fedc commit e5604ee

File tree

10 files changed

+137
-47
lines changed

10 files changed

+137
-47
lines changed

Xamarin.Forms.ControlGallery.Android/CustomRenderers.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ protected override void UpdateMenuItemIcon(Context context, IMenuItem menuItem,
115115
if (toolBarItem.IconImageSource is FileImageSource fileImageSource)
116116
{
117117
var name = IOPath.GetFileNameWithoutExtension(fileImageSource.File);
118-
var id = Xamarin.Forms.Platform.Android.ResourceManager.GetDrawableByName(name);
118+
var id = context.GetDrawableId(name);
119119
if (id != 0)
120120
{
121121
if ((int)Build.VERSION.SdkInt >= 21)

Xamarin.Forms.ControlGallery.Android/FormsAppCompatActivity.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ protected override void OnCreate(Bundle bundle)
5151
#endif
5252
Forms.Init(this, bundle);
5353

54+
// null out the assembly on the Resource Manager
55+
// so all of our tests run without using the reflection APIs
56+
// At some point the Resources class types will go away so
57+
// reflection will stop working
58+
ResourceManager.Init(null);
59+
5460
FormsMaps.Init(this, bundle);
5561
FormsMaterial.Init(this, bundle);
5662
AndroidAppLinks.Init(this);

Xamarin.Forms.Platform.Android.UnitTests/ButtonTests.cs

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Xamarin.Forms;
1313
using Xamarin.Forms.CustomAttributes;
1414
using AColor = Android.Graphics.Color;
15+
using AContextThemeWrapper = Android.Support.V7.View.ContextThemeWrapper;
1516

1617
namespace Xamarin.Forms.Platform.Android.UnitTests
1718
{
@@ -95,25 +96,26 @@ public void StyleTextAllCapsSettingIsRespected()
9596
}
9697

9798
// This is the ideal test for Issue11703. It's currently being tabled due to a Resource linking bug that we're working out with Android team
98-
//[Category("Button")]
99-
//[Description("Account for user's setting of styles property textAllCaps")]
100-
//[Issue(IssueTracker.Github, 11703, "[Bug] Android textAllCaps no longer works", issueTestNumber: 1)]
101-
//[TestCase(false)]
102-
//[TestCase(true)]
103-
//public void StyleTextAllCapsSettingIsRespected(bool allCaps)
104-
//{
105-
// ContextThemeWrapper contextThemeWrapper = null;
106-
// if (allCaps)
107-
// contextThemeWrapper = new ContextThemeWrapper(Context, Resource.Style.TextAllCapsStyleTrue);
108-
// else
109-
// contextThemeWrapper = new ContextThemeWrapper(Context, Resource.Style.TextAllCapsStyleFalse);
99+
/*[Category("Button")]
100+
[Description("Account for user's setting of styles property textAllCaps")]
101+
[Issue(IssueTracker.Github, 11703, "[Bug] Android textAllCaps no longer works", issueTestNumber: 1)]
102+
[TestCase(false)]
103+
[TestCase(true)]
104+
public async Task StyleTextAllCapsSettingIsRespected(bool allCaps)
105+
{
106+
AContextThemeWrapper contextThemeWrapper = null;
107+
if (allCaps)
108+
contextThemeWrapper = new AContextThemeWrapper(Context, Context.GetStyle("TextAllCapsStyleTrue"));
109+
else
110+
contextThemeWrapper = new AContextThemeWrapper(Context, Context.GetStyle("TextAllCapsStyleFalse"));
110111
111-
// var button = new Button { Text = "foo" };
112-
// var buttonControl = GetRenderer(button, contextThemeWrapper).View as AppCompatButton;
113-
// var initialTextTransform = buttonControl.TransformationMethod;
112+
var button = new Button { Text = "foo" };
113+
var initialTextTransform = await GetControlProperty(button, x => x.TransformationMethod);
114114
115-
// Assert.AreEqual(allCaps, initialTextTransform is AllCapsTransformationMethod);
116-
//}
115+
// when set through a style the type is an internal version of AllCapsTransformationMethod
116+
string typeName = $"{initialTextTransform}";
117+
Assert.AreEqual(allCaps, typeName.Contains("AllCapsTransformationMethod"));
118+
}*/
117119

118120
}
119121
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Android.Views;
4+
using NUnit.Framework;
5+
6+
namespace Xamarin.Forms.Platform.Android.UnitTests
7+
{
8+
[TestFixture]
9+
public class ResourceManagerTests : PlatformTestFixture
10+
{
11+
[Test, Category("Resource")]
12+
[Description("Retrieve Resources by Name")]
13+
public void RetrieveResourcesByName()
14+
{
15+
ResourceManager.Init(null);
16+
ResourceManager.DrawableClass = null;
17+
ResourceManager.LayoutClass = null;
18+
ResourceManager.ResourceClass = null;
19+
ResourceManager.StyleClass = null;
20+
21+
Assert.Greater(ResourceManager.GetDrawableId(this.Context, "DrawableTEST"), 0);
22+
Assert.Greater(ResourceManager.GetDrawableId(this.Context, "DrawableTEST.png"), 0);
23+
Assert.Greater(ResourceManager.GetLayout(this.Context, "LayoutTest"), 0);
24+
Assert.Greater(ResourceManager.GetStyle(this.Context, "TextAllCapsStyleTrue"), 0);
25+
Assert.Greater(ResourceManager.GetResource(this.Context, "namewith.adot"), 0);
26+
Assert.Greater(ResourceManager.GetResource(this.Context, "namewith_adot"), 0);
27+
28+
}
29+
}
30+
}
Loading
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<android.support.design.widget.CoordinatorLayout
3+
xmlns:android="http://schemas.android.com/apk/res/android"
4+
xmlns:app="http://schemas.android.com/apk/res-auto"
5+
android:layout_width="match_parent"
6+
android:layout_height="match_parent"
7+
>
8+
9+
<android.support.design.widget.AppBarLayout
10+
android:id="@+id/namewith.adot"
11+
android:layout_width="match_parent"
12+
android:layout_height="wrap_content"
13+
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
14+
>
15+
16+
<android.support.v7.widget.Toolbar
17+
android:layout_width="match_parent"
18+
android:layout_height="?attr/actionBarSize"
19+
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
20+
21+
</android.support.design.widget.AppBarLayout>
22+
23+
</android.support.design.widget.CoordinatorLayout>

Xamarin.Forms.Platform.Android.UnitTests/Xamarin.Forms.Platform.Android.UnitTests.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
<Compile Include="ButtonTests.cs" />
7171
<Compile Include="BackgroundTests.cs" />
7272
<Compile Include="TestActivity.cs" />
73+
<Compile Include="ResourceManagerTests.cs" />
7374
</ItemGroup>
7475
<ItemGroup>
7576
<PackageReference Include="NUnit">
@@ -97,6 +98,12 @@
9798
</ItemGroup>
9899
<ItemGroup>
99100
<AndroidResource Include="Resources\values\styles.xml" />
101+
<AndroidResource Include="Resources\layout\LayoutTest.axml" />
102+
<AndroidResource Include="Resources\drawable\DrawableTest.png" />
103+
</ItemGroup>
104+
<ItemGroup>
105+
<Folder Include="Resources\drawable\" />
106+
<Folder Include="Resources\layout\" />
100107
</ItemGroup>
101108
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
102109
</Project>

Xamarin.Forms.Platform.Android/Platform.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,7 @@ void GetNewMasterDetailToggle()
803803
if (fileImageSource == null)
804804
throw new InvalidOperationException("Icon property must be a FileImageSource on Master page");
805805

806-
int icon = ResourceManager.GetDrawableByName(fileImageSource);
806+
int icon = _activity.GetDrawableId(fileImageSource);
807807

808808
FastRenderers.AutomationPropertiesProvider.GetDrawerAccessibilityResources(_activity, CurrentMasterDetailPage, out int resourceIdOpen, out int resourceIdClose);
809809
#pragma warning disable 618 // Eventually we will need to determine how to handle the v7 ActionBarDrawerToggle for AppCompat

Xamarin.Forms.Platform.Android/Renderers/AndroidGIFImageParser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ public override bool SelectDrawable(int index)
194194
InJustDecodeBounds = true
195195
};
196196

197-
int drawableIdentifier = ResourceManager.GetDrawableByName(file);
197+
int drawableIdentifier = context.GetDrawableId(file);
198198

199199
if (drawableIdentifier != 0)
200200
{

Xamarin.Forms.Platform.Android/ResourceManager.cs

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public static class ResourceManager
2929
static Assembly _assembly;
3030
static Type FindType(string name, string altName)
3131
{
32-
return _assembly.GetTypes().FirstOrDefault(x => x.Name == name || x.Name == altName);
32+
return _assembly?.GetTypes().FirstOrDefault(x => x.Name == name || x.Name == altName);
3333
}
3434
static Type _drawableClass;
3535
static Type _resourceClass;
@@ -93,7 +93,7 @@ public static Type LayoutClass {
9393
if (imageSource is FileImageSource fileImageSource)
9494
{
9595
var file = fileImageSource.File;
96-
var id = IdFromTitle(file, DrawableClass);
96+
var id = IdFromTitle(file, DrawableClass, "drawable", context);
9797

9898
// try the drawables via id
9999
if (id != 0)
@@ -353,29 +353,47 @@ public static Drawable GetDrawable(this Context context, string name)
353353
return AndroidAppCompat.GetDrawable(context, id);
354354
}
355355

356+
public static int GetDrawableId(this Context context, string title)
357+
{
358+
return IdFromTitle(title, DrawableClass, _drawableDefType, context);
359+
}
360+
361+
[Obsolete("GetDrawableByName(string) is obsolete as of version 4.8. "
362+
+ "Please use GetDrawableId(string, context) instead.")]
356363
public static int GetDrawableByName(string name)
357364
{
358-
return IdFromTitle(name, DrawableClass);
365+
return IdFromTitle(name, DrawableClass, _drawableDefType, Forms.ApplicationContext);
359366
}
360367

368+
[Obsolete("GetResourceByName(string) is obsolete as of version 4.8. "
369+
+ "Please use GetResource(string, context) instead.")]
361370
public static int GetResourceByName(string name)
362371
{
363-
return IdFromTitle(name, ResourceClass);
372+
return IdFromTitle(name, ResourceClass, "id", Forms.ApplicationContext);
373+
}
374+
375+
public static int GetResource(this Context context, string title)
376+
{
377+
return IdFromTitle(title, ResourceClass, "id", context);
364378
}
365379

380+
[Obsolete("GetLayoutByName(string) is obsolete as of version 4.8. "
381+
+ "Please use GetLayout(string, context) instead.")]
366382
public static int GetLayoutByName(string name)
367383
{
368-
return IdFromTitle(name, LayoutClass);
384+
return IdFromTitle(name, LayoutClass, "layout", Forms.ApplicationContext);
369385
}
370386

371387
public static int GetLayout(this Context context, string name)
372388
{
373389
return IdFromTitle(name, LayoutClass, "layout", context);
374390
}
375391

392+
[Obsolete("GetStyleByName(string) is obsolete as of version 4.8. "
393+
+ "Please use GetStyle(string, context) instead.")]
376394
public static int GetStyleByName(string name)
377395
{
378-
return IdFromTitle(name, StyleClass);
396+
return IdFromTitle(name, StyleClass, "style", Forms.ApplicationContext);
379397
}
380398

381399
public static int GetStyle(this Context context, string name)
@@ -388,24 +406,14 @@ public static void Init(Assembly masterAssembly)
388406
_assembly = masterAssembly;
389407
}
390408

391-
static int IdFromTitle(string title, Type type)
392-
{
393-
if (title == null)
394-
return 0;
395-
396-
string name = IOPath.GetFileNameWithoutExtension(title);
397-
int id = GetId(type, name);
398-
return id;
399-
}
400-
401409
static int IdFromTitle(string title, Type resourceType, string defType, Resources resource)
402410
{
403411
return IdFromTitle(title, resourceType, defType, resource, AppCompat.Platform.GetPackageName());
404412
}
405413

406414
static int IdFromTitle(string title, Type resourceType, string defType, Context context)
407415
{
408-
return IdFromTitle(title, resourceType, defType, context.Resources, context.PackageName);
416+
return IdFromTitle(title, resourceType, defType, context?.Resources, context?.PackageName);
409417
}
410418

411419
static int IdFromTitle(string title, Type resourceType, string defType, Resources resource, string packageName)
@@ -414,24 +422,38 @@ static int IdFromTitle(string title, Type resourceType, string defType, Resource
414422
if (title == null)
415423
return id;
416424

417-
string name = IOPath.GetFileNameWithoutExtension(title);
425+
string name;
418426

419-
id = GetId(resourceType, name);
427+
if (defType == "style" || (resourceType != null && resourceType == StyleClass))
428+
name = title;
429+
else
430+
name = title.ToLower();
420431

421-
if (id > 0)
432+
if (defType == _drawableDefType || (resourceType != null && resourceType == DrawableClass))
433+
name = IOPath.GetFileNameWithoutExtension(name);
434+
435+
if ((id = SearchByIdentifier(name, defType, resource, packageName)) > 0)
422436
return id;
423437

424-
if (packageName != null)
438+
// When searching by reflection you would use a "_" instead of a "."
439+
// So this accounts for cases where users were searching with an "_"
440+
if ((id = SearchByIdentifier(name.Replace("_", "."), defType, resource, packageName)) > 0)
441+
return id;
442+
443+
int SearchByIdentifier(string n, string d, Resources r, string p)
425444
{
426-
id = resource.GetIdentifier(name, defType, packageName);
445+
int returnValue = 0;
427446

428-
if (id > 0)
429-
return id;
430-
}
447+
if (p != null)
448+
returnValue = r.GetIdentifier(n, d, p);
431449

432-
id = resource.GetIdentifier(name, defType, null);
450+
if (returnValue == 0)
451+
returnValue = r.GetIdentifier(n, d, null);
452+
453+
return returnValue;
454+
}
433455

434-
return id;
456+
return GetId(resourceType, name);
435457
}
436458

437459
static int GetId(Type type, string memberName)

0 commit comments

Comments
 (0)