I am trying to bind an Android PDF library in a Xamarin Android Binding project, but a unnecessary "override" modifier is added to a property:
public partial class ReaderView : global::Android.Widget.AdapterView, [...] {
// ...
public override unsafe global::Android.Widget.IAdapter Adapter {
// Metadata.xml XPath method reference: path="/api/package[#name='com.artifex.mupdfdemo']/class[#name='ReaderView']/method[#name='getAdapter' and count(parameter)=0]"
[Register ("getAdapter", "()Landroid/widget/Adapter;", "GetGetAdapterHandler")]
get {
// ...
}
// Metadata.xml XPath method reference: path="/api/package[#name='com.artifex.mupdfdemo']/class[#name='ReaderView']/method[#name='setAdapter' and count(parameter)=1 and parameter[1][#type='android.widget.Adapter']]"
[Register ("setAdapter", "(Landroid/widget/Adapter;)V", "GetSetAdapter_Landroid_widget_Adapter_Handler")]
set {
// ...
}
}
// ...
}
I didn't find anything about adding/removing modifiers like "override", or "virtual" in the documentation.
I tried this without success:
<attr path="/api/package[#name='com.artifex.mupdfdemo']/class[#name='ReaderView']/method[#name='getAdapter' and count(parameter)=0]" name="override">false</attr>
<attr path="/api/package[#name='com.artifex.mupdfdemo']/class[#name='ReaderView']/method[#name='setAdapter' and count(parameter)=1 and parameter[1][#type='android.widget.Adapter']]" name="override">false</attr>
Do you guys have any idea about how to do this?
Edit 1: The Java project is on GitHub: https://github.com/asimmon/MuPDF-for-Android and here is a direct link to the file ReaderView.java.
Edit 2: The Xamarin Binding Project is on GitHub too, you will find the Jar library: https://github.com/asimmon/MuPDF-for-Xamarin-Android
The solution is to modify the visibility of the method in Metadata.xml:
<attr
path="/api/package[#name='com.artifex.mupdfdemo']/class[#name='ReaderView']/method[#name='getAdapter']"
name="visibility">public</attr>
This effectively removes the override keyword from your method's signature.
Related
I'm creating a costum Android Lint Inspection and I need to register the inspection, to be run. Where do I need to register it?
I've already tried to register the inspection which provides the inspection inside plugin.xml file.
The actual inspection:
class HardcodedDimensionsInspection : AndroidLintInspectionBase("Hardcoded dimensions", HardcodedDimensDetector.ISSUE) {
override fun getShortName(): String {
return "AndroidLintHardcodedDimension"
}
}
The entry in plugin.xml file
<extensions defaultExtensionNs="com.intellij">
<!-- Add your extensions here -->
<!-- <inspectionToolProvider implementation="JavaInspectionProvider"/>-->
<globalInspection shortName="AndroidLintHardcodedDimension" displayName="Hardcoded dimensions"
enabledByDefault="true" level="WARNING"
implementationClass="HardcodedDimensionsInspection"/>
</extensions>
The actual detector
class HardcodedDimensDetector : LayoutDetector() {
override fun getApplicableAttributes(): Collection<String>? {
return Arrays.asList(
// Layouts
ATTR_TEXT
)
}
override fun appliesTo(folderType: ResourceFolderType): Boolean {
return (folderType == ResourceFolderType.LAYOUT ||
folderType == ResourceFolderType.MENU ||
folderType == ResourceFolderType.XML)
}
override fun visitAttribute(context: XmlContext, attribute: Attr) {
val value = attribute.value
}
companion object {
/** The main issue discovered by this detector */
#JvmField
val ISSUE = Issue.create(
id = "HardcodedDimension",
briefDescription = "Hardcoded dimens",
explanation = """
Brief
""",
category = Category.I18N,
priority = 5,
severity = Severity.ERROR,
implementation = Implementation(
HardcodedDimensDetector::class.java,
Scope.RESOURCE_FILE_SCOPE
)
)
}
}
I've expected to hit the breakpoints in any of the functions for Detector but the code is never called. Seems like my detector is not registered. Can you please point me to the missing part, is there a class where I should register my Detector?
Thank you.
The link to the full project: https://github.com/magicbytes/Android-Lint-Inspection
I don't see anything obvious wrong from these snippets. Could you please post on our forum and link to the full sources of your plugin? Thanks. https://intellij-support.jetbrains.com/hc/en-us/community/topics/200366979-IntelliJ-IDEA-Open-API-and-Plugin-Development
I have a workaround for now, not sure it's the official way to do it. Android Lint has a registry with all the Issue classes (built-in), the class is called LintIdeIssueRegistry. When it runs the Android Lint, it's looking in this registry for Issue processors. Since the list is hardcoded, we need to inject ours in the list. I'm using the following code for that:
val registry = LintIdeIssueRegistry()
val issue = registry.getIssue(HardcodedDimensDetector.ISSUE.id)
if (issue == null) {
val list = registry.issues as MutableList<Issue>
list.add(HardcodedDimensDetector.ISSUE)
}
Hopefully in future we will have a method called addIssue inside the LintIdeIssueRegistry.
I'm not sure what I'm doing wrong, but even though I'm definitely on the UI thread, I'm consistently getting the error " 'The application called an interface that was marshalled for a different thread.'" when constructing Xaml controls in C++.
See the following basic example, which uses a stripped down version of the default C++/WinRT CoreApplication template:
#include "pch.h"
using namespace winrt;
using namespace Windows;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::Foundation::Numerics;
using namespace Windows::UI;
using namespace Windows::UI::Core;
using namespace Windows::UI::Composition;
using namespace Windows::ApplicationModel::Activation;
struct App : implements<App, IFrameworkViewSource, IFrameworkView> {
CompositionTarget m_target{nullptr};
IFrameworkView CreateView() { return *this; }
void Initialize(CoreApplicationView const &) {}
void Load(hstring const &) {}
void Uninitialize() {}
void Run() {
CoreWindow window = CoreWindow::GetForCurrentThread();
winrt::Windows::UI::Xaml::Controls::TextBox textbox; // Crashes here
CoreDispatcher dispatcher = window.Dispatcher();
dispatcher.ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit);
}
void SetWindow(CoreWindow const &) {
Compositor compositor;
ContainerVisual root = compositor.CreateContainerVisual();
m_target = compositor.CreateTargetForCurrentView();
m_target.Root(root);
}
};
int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) { CoreApplication::Run(make<App>()); }
I've tried using window.Dispatcher().HasThreadAccess() to verify that I'm on the correct thread to be making UI calls, and it always returns true.
I've also tried calling RunAsync() from the window's Dispatcher and constructing a Xaml object in a lambda passed to this method, and it still has exactly the same result. HasThreadAccess returns true here too.
Can anyone explain to me where I'm going wrong here? Is constructing Xaml objects not supported in C++?
[edit]
Here's a sample project that reproduces the issue, again based on the default CoreWindow C++/WinRT template:
https://github.com/lyptt/CoreApp1
Turns out the CoreApplication-based template does not support anything from the Xaml namespace, as it's intended more towards providing a thin UWP layer for games, etc.
To get Xaml support you need to use the full template instead, then things magically start to work.
I just want use react-native-camera in my react-native project but has an error, I need help, I don't know what happened about this error. Looking forward to your answer, Thanks.
error info
android/app/build.gradle
There are two main possibilities:
Add below line in build.gradle under compile project(':react-native-camera')
compile (project(':react-native-camera')) {
exclude group: "com.android.support"
}
As Camera module is used same TAG name as default native camera will use it:
--> put code into react-native-camera --> src --> main --> java --> com.lwansbrough.RCTCamera --> RCTCameraModule
1) You need to add RCTCameraModule as a tag:
public class RCTCameraModule extends ReactContextBaseJavaModule
implements MediaRecorder.OnInfoListener, MediaRecorder.OnErrorListener, LifecycleEventListener {
private static final String TAG = "RCTCameraModule";
...
}
2) Add this method
#Override
public String getName() {
return "RCTCameraModule";
}
Hope this will help you :)
I am working on disabling copy/paste option menus on xamarin forms Entry, I am able to disable copy option using IsPassword=true attribute but this attribute also converts the normal input field to password field, which is not a requirement.
<Entry IsPassword="true" Placeholder="Password" TextColor="Green" BackgroundColor="#2c3e50" />
Thanks in advance.
This has to do with how Forms functions. Using iOS as the example here, the CanPerform override referred to in the other answer's Bugzilla issue is using the UIMenuController as the withSender and not the UITextField itself that might otherwise be expected. This is because the EntryRenderer class is a ViewRenderer<TView, TNativeView> type and subsequently is using whatever TNativeView (in this case, the UITextView) has in its CanPerform. Because nothing is going to be overridden by default, one still sees all of the cut/copy/paste options in the UIMenuController.
As a result, there would be a couple options. You could first make the modification where if you don't want copy/paste but are fine with getting rid of everything else, you can use UIMenuController.SharedMenuController.SetMenuVisible(false, false) in a custom renderer inheriting from EntryRenderer. If you look around on SO, there are similar questions where this is a possible route.
Alternatively, you can create a "true" custom renderer inheriting from ViewRenderer<TView, TNativeView> as ViewRenderer<Entry, YourNoCopyPasteUITextFieldClassName>. The class inheriting from UITextField can then override CanPerform as something like follows:
public override bool CanPerform(Selector action, NSObject withSender)
{
if(action.Name == "paste:" || action.Name == "copy:" || action.Name == "cut:")
return false;
return base.CanPerform(action, withSender);
}
This will require more effort because the custom renderer will not have the same behavior as the EntryRenderer, but as Xamarin.Forms is now open source, you could look to it for some ideas as to how the EntryRenderer functions normally. Something similar would likely have to be done for Android.
Edit: For Android, you can probably use this SO answer as a starting point: How to disable copy/paste from/to EditText
Another custom renderer, this time inheriting from ViewRenderer<Entry, EditText>, and create a class inside of it like this (in the most basic form):
class Callback : Java.Lang.Object, ActionMode.ICallback
{
public bool OnActionItemClicked(ActionMode mode, IMenuItem item)
{
return false;
}
public bool OnCreateActionMode(ActionMode mode, IMenu menu)
{
return false;
}
public void OnDestroyActionMode(ActionMode mode)
{
}
public bool OnPrepareActionMode(ActionMode mode, IMenu menu)
{
return false;
}
}
Then, in your OnElementChanged method, you can set the native control and the CustomSelectionActionModeCallback value:
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.CustomSelectionActionModeCallback = new Callback();
}
}
Doing something like the following appears to disable all of the copy/paste/cut functionality on the custom entry as far as the toolbar goes. However, you can still long click to show the paste button, to which I've poked around a bit hadn't found an answer yet beyond setting LongClickable to false. If I do find anything else in that regard, I'd make sure to update this.
I'm trying to create a Java Binding Library for BugSense, but one of the methods has a parameter named "params" which is a reserved word in C#. I've tried to use the Metadata.xml file to rename it, but I can't figure out how to access the class, let alone the method or it's parameter.
Here is the problem code it's generating:
namespace Com.Bugsense.Trace {
[global::Android.Runtime.Register ("com/bugsense/trace/ActivityAsyncTask", DoNotGenerateAcw=true)]
internal partial class ActivityAsyncTaskInvoker : ActivityAsyncTask {
static IntPtr id_doInBackground_arrayLjava_lang_Object_;
[Register ("doInBackground", "([Ljava/lang/Object;)Ljava/lang/Object;", "GetDoInBackground_arrayLjava_lang_Object_Handler")]
protected override global::Java.Lang.Object DoInBackground (global::Java.Lang.Object[] params)
{
if (id_doInBackground_arrayLjava_lang_Object_ == IntPtr.Zero)
id_doInBackground_arrayLjava_lang_Object_ = JNIEnv.GetMethodID (class_ref, "doInBackground", "([Ljava/lang/Object;)Ljava/lang/Object;");
IntPtr native_params = JNIEnv.NewArray (params);
global::Java.Lang.Object __ret = Java.Lang.Object.GetObject<global::Java.Lang.Object> (JNIEnv.CallObjectMethod (Handle, id_doInBackground_arrayLjava_lang_Object_, new JValue (native_params)), JniHandleOwnership.TransferLocalRef);
if (params != null) {
JNIEnv.CopyArray (native_params, params);
JNIEnv.DeleteLocalRef (native_params);
}
return __ret;
}
}
}
Here is my mapping, which I feel should work, but just refuses to.
<attr path="/api/package[#name='com.bugsense.trace']/class[#name='ActivityAsyncTaskInvoker']/method[#name='doInBackground']/parameter[#name='params']" name="managedName">#params</attr>
I've tried everything I can think of. Please, HELP!
So, turns out it's just a bug in the current version of Mono for Android. If you update to the 4.2.4 build, which is in beta, everything compiles fine.