What to do with the boolean return of the OnTouchListener (MapView)? - android-studio

I'm working on an app that uses a MapView instance called map. At a certain point I want to know if the map has been touched. To that purpose Android Studio generated this boolean return callback method (see below) for the OnTouchListener.
MapView map;
map = findViewById(R.id.view_map);
map.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch (View v) {
return false;
}
});
As you can see, unlike in a simple OnClickListener, you are apparently not free to write the method that should follow a touch event. That method appears to be fixed at return false. You cannot change it to e.g. a void method.
What is the purpose of that return? To where/what will false be returned? Is it perhaps stored in the object map, as a field of the MapView class? If I knew, I could initialize that field/variable to true, wait for the OnTouchListener to change it to false, and then use that information elsewhere in the app (e.g. to suspend the app's instruction to continuously center the map on the current GPS position).

Related

How can I execute code from the Release / Release All buttons in the Release AR Documents screen

I've got a customization to the Invoice & Memo screen where I execute some custom code (web service calls) when the Release action is activated. This works fine - I knew how to replace the PXAction code and proceeded from there. Now I want to use the Release AR Documents processing screen to do the same thing, but I'm having trouble understanding where / what to override, or where to place my code.
I see the ARDocumentRelease graph constructor with the SetProcessDelegate in the source code, but I'm not sure how to proceed - whether this is where I need to be looking or not. I need to execute my code for each line being released, using the RefNbr in my code.
Since it's an static method, you can't override it. Also, you can't do like it's done in the T300, because you are in processing graph and you can't override the release button with your own. I was able to achieve it by passing callback for each AR document that have been processed.
You can call the Initialize method of the ARDocumentRelease graph to override the logic like you said. After you just have to call ReleaseDoc that uses a callback parameter instead of using the default one.
Here's the code that I came with:
public class ARDocumentRelease_Extension : PXGraphExtension<ARDocumentRelease>
{
public override void Initialize()
{
ARSetup setup = Base.arsetup.Current;
Base.ARDocumentList.SetProcessDelegate(
delegate (List<BalancedARDocument> list)
{
List<ARRegister> newlist = new List<ARRegister>(list.Count);
foreach (BalancedARDocument doc in list)
{
newlist.Add(doc);
}
AddAdditionalLogicToRelease(newlist);
}
);
Base.ARDocumentList.SetProcessCaption("Release");
Base.ARDocumentList.SetProcessAllCaption("Release All");
}
public delegate void PostPorcessing(ARRegister ardoc, bool isAborted);
private void AddAdditionalLogicToRelease(List<ARRegister> newlist)
{
ARDocumentRelease.ReleaseDoc(newlist, true, null, delegate(ARRegister ardoc, bool isAborted) {
//Add your logic to handle each document
//Test to check if it was not aborted
});
}
}
Please note that you must always call static methods from within long running process and create necessary objects there.
Processing delegate logic is implemented as long running process which creates worker thread to execute the processing logic.
You have AddAdditionalLogicToRelease() method which requires object instance in order to call and will fail during thread context switches and hence the issue. So, you must have create object instance inside the thread context and then call instance method.
In general, method that gets called from long running processes are declared static and required objects/graphs are created inside this static method to do some work. See below example how to properly override ARDocumentRelease graph for this purpose:
public class ARDocumentRelease_Extension : PXGraphExtension<ARDocumentRelease>
{
public override void Initialize()
{
Base.ARDocumentList.SetProcessDelegate(
delegate (List<BalancedARDocument> list)
{
List<ARRegister> newlist = new List<ARRegister>(list.Count);
foreach (BalancedARDocument doc in list)
{
newlist.Add(doc);
}
// use override that allows to specify onsuccess routine
ARDocumentRelease.ReleaseDoc(newlist, true, null, (ardoc, isAborted) =>
{
//Custom code here, such as create your GL
});
}
);
}
}
I think it's the function
public static void ReleaseDoc(List<ARRegister> list, bool isMassProcess, List<Batch> externalPostList, ARMassProcessDelegate onsuccess)
under ARDocumentRelease businesss logic.

Windows universal Right to Left support

It is necessary to make the support of Right to Left style (both text and layout-s). I understand that when you set parent Grid's properties FlowDirection = "RightToLeft" in all child controls it inherited.
The question is - is there any default setting, which will shift all we need in app? Or should I set every parent greeds FlowDirection by some king of flag and set this flag as FlowDirection = "RightToLeft" if we, for example in in Arab countries?
If you are going to support any right to left language will need to have a right to left layout too. You don't need to change FlowDirection property of all of the elements since it is inherited by child elements.
MSDN:
An object inherits the FlowDirection value from its parent in the
object tree. Any element can override the value it gets from its
parent. If not specified, the default FlowDirection is LeftToRight
So usually you need to set the property once for root element/frame of the Window.
However, some elements like FontIcon and Image does not mirror automatically. FontIcon has a MirroredWhenRightToLeft property:
You can set the MirroredWhenRightToLeft property to have the glyph
appear mirrored when the FlowDirection is RightToLeft. You typically
use this property when a FontIcon is used to display an icon as part
of a control template and the icon needs to be mirrored along with the
rest of the control
For Image, you need to flip the image by transforms.
Edit:
You can set the property in the Application class where you create the main frame/page:
// Part of the App.xaml.cs in default UWP project template:
protected override void OnLaunched(LaunchActivatedEventArgs e) {
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached) {
this.DebugSettings.EnableFrameRateCounter = true;
}
#endif
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null) {
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) {
//TODO: Load state from previously suspended application
}
//**********************
// Set flow direction
// *********************
if (System.Globalization.CultureInfo.CurrentCulture.TextInfo.IsRightToLeft) {
rootFrame.FlowDirection = FlowDirection.RightToLeft;
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
...
...
If you don't want to use code behind (I think its OK to use it for this scenario), you can implement IValueConverter (Not recommended):
public class RightToLeftConverter : IValueConverter {
public object Convert(object value, Type targetType,
object parameter, string language) {
if (System.Globalization.CultureInfo.CurrentCulture.TextInfo.IsRightToLeft) {
return FlowDirection.RightToLeft;
}
return FlowDirection.LeftToRight;
}
public object ConvertBack(object value, Type targetType,
object parameter, string language)
{
throw new NotImplementedException();
}
}
and use it in XAML:
<Page
...
...
FlowDirection="{Binding Converter={StaticResource RightToLeftConverter}}">

Why are the height and width of the content View zero in Robolectric?

Here's a failing test:
#RunWith(RobolectricTestRunner.class)
public class FailTest {
#Test
public void heightAndWidth_shouldNotBeZero() {
TestActivity testActivity = Robolectric.buildActivity(TestActivity.class).create().resume().visible().get();
View contentView = testActivity.findViewById(69);
Assertions.assertThat(contentView.getWidth()).isNotZero();
Assertions.assertThat(contentView.getHeight()).isNotZero();
}
private static class TestActivity extends Activity {
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout contentView = new LinearLayout(this);
contentView.setId(69);
contentView.setLayoutParams(new LayoutParams(666, 666));
setContentView(contentView);
}
}
}
As you can see, I'm calling the visible() method on the ActivityController and driving the Activity lifecycle the correct way. Quoting the documentation:
Wait, What's This visible() Nonsense?
Turns out that in a real Android app, the view hierarchy of an
Activity is not attached to the Window until sometime after onCreate()
is called. Until this happens, the Activity's views do not report as
visible. This means you can't click on them (amongst other unexpected
behavior). The Activity's hierarchy is attached to the Window on a
device or emulator after onPostResume() on the Activity. Rather than
make assumptions about when the visibility should be updated,
Robolectric puts the power in the developer's hands when writing
tests.
So when do you call it? Whenever you're interacting with the views
inside the Activity. Methods like Robolectric.clickOn() require that
the view is visible and properly attached in order to function. You
should call visible() after create().
It seems as though I'm doing all I need to do. So why am I getting no height/width?
There is no layout pass in Robolectric, hence the view dimensions are always zero.
https://github.com/robolectric/robolectric/issues/819

Dialog values with MvvmCross, ActionBarSherlock and DialogFragment

I have a bunch of different libraries trying to work together and I'm pretty close but there's just one issue.
I have created a class called SherlockDialogFragment inheriting from SherlockFragment (rather than using the SherlockListFragment - this is because of the issue with the keyboard that's covered here). Here is my code:
public class SherlockDialogFragment : SherlockFragment
{
public RootElement Root
{
get { return View.FindViewById<LinearDialogScrollView>(Android.Resource.Id.List).Root; }
set { View.FindViewById<LinearDialogScrollView>(Android.Resource.Id.List).Root = value; }
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var ignored = base.OnCreateView(inflater, container, savedInstanceState);
var layout = new LinearLayout(Activity) { Orientation = Orientation.Vertical };
var scroll_view = new LinearDialogScrollView(Activity)
{
Id = Android.Resource.Id.List,
LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.FillParent)
};
layout.AddView(scroll_view);
return layout;
}
}
I then do the regular thing of creating an eventsource class which inherits from this but also uses IMvxEventSourceFragment, then the actual fragment class (which I call MvxSherlockDialogFragment) which inherits the eventsource class, as well as IMvxFragmentView.
That all works fine (and indeed I've created a SherlockDialogActivity the same way and it's fine), however the one issue is when I use this fragment on a screen with tabs (i'm using a class I made similarly to above called MvxSherlockFragmentActivity). When switching to the tab with the dialog, the view appears fine, even with pre-populated data. However the issue is when I switch away from that fragment/tab, and then back to it, the dialog elements all have the same value.
In my particular example, it's a login page with a username and password. When I first go into the fragment, everything is fine. When I go out and back in, the password value is in both the username field and the password field.
I'm sure it's got something to do with the SherlockDialogFragment class - in the SherlockDialogActivity class I also have this bit:
public override void OnContentChanged()
{
base.OnContentChanged();
var list = FindViewById<LinearDialogScrollView>(Android.Resource.Id.List);
if (list == null)
{
throw new RuntimeException("Your content must have a ViewGroup whose id attribute is Android.Resource.Id.List and is of type LinearDialogScrollView");
}
list.AddViews();
}
However this doesn't work in a fragment because there's no OnContentChanged event. Also, another difference is that in the SherlockDialogActivity, the layout is being created ONCE in the OnCreate event - however in the SherlockFragmentActivity I've got it being created each time the fragment is viewed. I know that's probably not the best way, but I tried to do it in OnCreate and save it in a variable and then return that variable in OnCreateView, but android didn't like that...
Ok I feel like an idiot. I was creating/binding on OnViewCreated - however I need to do all my binding in OnStart - I think I was following some (possibly old) sample code from Stuart.
Obviously for a regular activity I'm using OnCreate but this doesn't work on a fragment, because the view is not initialised there - it's initialised at OnCreateView.
So for future reference - do all binding in OnStart!

Monotouch-Dialog ReloadData does not reloads data?

I want to use monotouch dialog as not editable data display for some numeric values. But calling DialogViewController.ReloadData does not updates data from binded object.
class AccountFormModel
{
[Section("Account data", "")]
[Caption("Balance")]
public string balance;
}
...
private void InitComponents()
{
accountFormModel = new AccountFormModel();
accountFormModel.balance = "TestTestTest";
bc = new BindingContext(this, accountFormModel, "AccountData");
dialogViewController = new DialogViewController(bc.Root);
dialogViewController.Autorotate = true;
}
private void RefreshData()
{
string b = SomeDatasource.Account.Balance.ToString("N4");
accountFormModel.balance = "$" + b;
dialogViewController.ReloadData();
}
Debugging shows that accountFormModel.balance in refreshData method is set to right value, but nothing changes on form in simulator (stays TestTestTest). What i'm doing wrong?
DialogViewController when using reflection does the binding once initially, and only when you FetchData() is the data transferred back to your class.
What happens is that the BindingContext will basically create the model from your data (balance in this case) effectively making a copy of your data at this point. When you call ReloadData() this is reloading the data from the copy, and that is why you do not see a change. Although this could be changed to have some method on the BindingContex to repopulate the data, this is not currently the case.
The Reflection API for MonoTouch.Dialog is very limited, I strongly advise you that for anything non-trivial, you use the Elements API. Most of the samples in MonoTouch.Dialog use that API, as it gives you full control of the dialog.

Resources