TalkBack is able to detect accessibility identifiers in my React Native 0.35.0 android app from non-active scenes I previously navigated through. How do I prevent this so only the current scene is used when identifying accessibility identifiers?
For example I have the first page of my app render a ListView of items. These work as expected with accessibility identifiers where any item can be selected.
The problem is when navigate to the next page, a page that only has one line of text, all the ListView items from the previous scene are still accessible when viewing the new scene!
I am using NavigationExperimental, specifically NavigationCardStack, for navigation. I'm aware NavigationCardStack will render each visited scenes in the stack but am looking to find a way so only the active scene is selectable.
So far I've tried implementing a version of NavigationExperimental that only renders the active scene. While it solves this problem the navigation animations are ruined and navigating back through the app must re-create each scene which creates a sluggish and unacceptable experience in my opinion.
While I don't love the solution I thought setting accessible={false} on every component from the first page may work. Unfortunately even this still left the Text components accessible. If it had worked I could have set accessible to NavigationExperimental's property scene.isActive.
I was able to resolve this issue. In React Native there is an attribute Android can set called importantForAccessibility. It's a little more intensive than I'd prefer but I implemented my own NavigationCardStack and NavigationCard (extended React Native's version to add my own logic in render).
Essentially while iterating over each scene in NavigationCardStack I pass a new property, isActiveScreen which I set to true only on the active scene by inspecting the current index.
Then in NavigationCard I leverage importantForAccessibility by adding
importantForAccessibility={this.props.isActiveScreen ? 'yes' : 'no-hide-descendants'}
In this way on android only my currently visible scene has accessibility enabled while all other scenes in the stack have no-hide-descendants set.
I have had the same issue using the react-navigation library. I was able to modify the react-navigation/src/views/CardStack/Card.jsin order to fix this which can be found here, I just modify the render method (Can't get the code to format :()
Card.js # Github
The following are my modifcations to this:
// Fixes an issue on Android whereby talkback/voiceover will pick up elements on a child view that is not active in the stack navigator
if(this.props.scene.isActive) {
importantForAccessibility='yes';
} else {
importantForAccessibility='no-hide-descendants';
}
return (
<Animated.View
pointerEvents={pointerEvents}
ref={this.props.onComponentRef}
style={[styles.main, style]}
importantForAccessibility={importantForAccessibility}
>
{children}
</Animated.View>
);
This fix has also been forked on github & published to NPM if anyone needs it as follows:
https://github.com/awseeley/react-navigation
https://www.npmjs.com/package/react-navigation-awseeley
Related
I have a custom view that renders part of itself (pink area) in onDraw. It does this, via a class instance set via adapter/binding. I have no problem with the 117 and details controls at design time. However, this pink area is resulting in a call to onDraw within Android Studio.
Everything's ok at runtime. However, I am getting (and rightfully so) an Android Studio error message - because the class that I use to do the drawing hasn't been instantiated.
So, my question is:
Can I detect, in code, whether or not the app is running (rendering really) inside AS (as opposed to having been deployed to an emulator or device)?**
It might be something like if (BuildConfig.DEBUG), or perhaps something [entirely] different. (There's certainly nothing [else] in the BuildDebug instance that'll help.)
Ultimately, I see my current
override fun onDraw(canvas: Canvas) {
:
:
puzzle.doSomething
replaced with something like:
if (!INSIDE_ANDROID_STUDIO)
puzzle.doSomething
I spent over an hour searching online. With no luck. It's hard to ask "How do I know if I'm running in the Android Studio IDE?" and not get a bazillion links concerning:
Why isn't Android Studio running [correctly]
How to tell if another app is running
How to tell if your app is in the fore or background
Why this or that isn't rendering correctly
But nothing on point. I did numerous searches of "UninitializedPropertyAccessException" and "Render problem" as well.
You can do it by checking what returns the isInEditMode() method. If true your view is displayed in AS or other tool, otherwise - it`s on a device.
Indicates whether this View is currently in edit mode. A View is usually in edit mode when displayed within a developer tool. For instance, if this View is being drawn by a visual user interface builder, this method should return true.
https://developer.android.com/reference/android/view/View#isInEditMode()
Is there any way to tell my Android app that do not accept outside app content being drawn on top of it? Overlays,... (but of course accept application generated overlays, diglogs, toasts,...).
Specifically to avoid the kind of attacks such as Cloack and Dagger:
http://thehackernews.com/2017/05/android-hacking-technique.html?m=1
http://cloak-and-dagger.org/#Demos
Do full-screen and video apps fully avoid it? And if do, how do they do?
Set filterTouchesWhenObscured to true. Or implement the method onFilterTouchEventForSecurity().
More info here: https://blog.devknox.io/tapjacking-android-prevent/
I'm programming an app using android studio. I want to know in which way I can do a tutorial that users will see only the first time that use the app. Tutorial like image or screenshoots
Can someone help me? Thanks
I encountered this thread while looking for a solution for running a tutorial only at the first time (as rbaleksandar suggested), so in case it will be helpful for someone someday, here's a template of a solution that works for me (using the SharedPreferences API):
#Override
protected void onResume() {
super.onResume();
String tutorialKey = "SOME_KEY";
Boolean firstTime = getPreferences(MODE_PRIVATE).getBoolean(tutorialKey, true);
if (firstTime) {
runTutorial(); // here you do what you want to do - an activity tutorial in my case
getPreferences(MODE_PRIVATE).edit().putBoolean(tutorialKey, false).apply();
}
}
EDIT - BONUS - If you're into app tutorial - I'm messing now with the ShowcaseView library (which is amazing - try it out). Apparently they have some shortcut for that issue using a method called singleShot(long) - its input is a key for the SharedPreferences, and it does the exact same thing - runs only in the first activation. Example of usage (taken from here):
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_shot);
Target viewTarget = new ViewTarget(R.id.button, this);
new ShowcaseView.Builder(this)
.setTarget(viewTarget)
.setContentTitle(R.string.title_single_shot)
.setContentText(R.string.R_string_desc_single_shot)
.singleShot(42)
.build();
}
You could always code your own solution, but, let us not reinvent the wheel.
Check this Android Library:
Tour Guide Repository
It allows you to add pointers in your screen, so the user knows where is he supposed to touch next.
It's pretty easy to use, you only need to point to the element you want the user to touch.
From the doc:
Let's say you have a button like this where you want user to click on:
Button button = (Button)findViewById(R.id.button);
You can add the tutorial pointer on top of it by:
TourGuide mTourGuideHandler = TourGuide.init(this).with(TourGuide.Technique.Click)
.setPointer(new Pointer())
.setToolTip(new ToolTip().setTitle("Welcome!").setDescription("Click on Get Started to begin..."))
.setOverlay(new Overlay())
.playOn(button);
Hope this helps!
Some links to libraries for creating introduction and/or tutorial screens.
Horizontal cards like Google Now:
https://github.com/PaoloRotolo/AppIntro
Tutorial screen:
https://github.com/amlcurran/ShowcaseView
As far as I understand the question is not How do I create a tutorial? (as the people who have already posted an answer have concluded) but instead How to show a tutorial upon first launch only?. So here are my two cents on this topic:
I'm not familiar with how your Android app stores its configuration data but I will assume that it's either in a database (SQLite) or a text file (plaintext, YAML, XML - whatever). Add a configuration entry to wherever the app's settings are being stored - something like tutorial_on : false, tutorial_on : 1 etc. depending on the format the configuration is represented in.
The way configurations work is that whenever an app (or software in general) is launched it has to be loaded in the app itself. So add the following to your app (where and how is up to you and your app design):
Check tutorial_on entry
If tutorial_on is set to true/1 whatever
2.1 Display tutorial
2.2 Change tutorial_on to false/0 whatever
2.3 Store the result in your configuration
Continue using the app
By doing so the first time your app launches the flag responsible for displaying the tutorial will be toggled and afterwards every time you start the app the toggle flag will be read leading to omitting the tutorial.
Personally I would suggest that you an option similar to Don't show tutorial anymore along with a description how to re-enable it (by triggering some action in that app's menu etc.). This has two major benefits:
Improved user experience - users like to have control (especially over trivial matters such as showing or hiding a tutorial). Whenever you take the control away from them, they get pissed off.
Enable your user to re-learn forgotten things - a general rule of thumb is to create apps that should not burden the user with a lot of stuff to remember. That is why things should be self-explanatory. However sometimes you may want to do that nonetheless. By adding the possibility that the user re-launches (by simply resetting the tutorial_on flag and repeating the steps from above) the tutorial allows just that - refreshing a user's memory.
I'm writing an Android app using Titanium Alloy.
This app has multiple View files and it is based on a lot of Windows elements.
Just for making a simple example, think about this:
I have two View files: index.xml (with its Controller index.js) and win02.xml (with its Controller win02.js). index.xml has a Button. I want to open win02 from index by pressing its Button and I want everything about index to be removed from memory so I avoid possible memory leaks.
Inside index.js, I put this code:
btn.addEventListener('click', function(e){
Alloy.createController('win02').getView().open();
});
And, in doing so, I am able to open the win02 Window. But how can I totally remove index? Thanks.
To remove a window you can call close() so $.index.close(); just after you create win02, that should do the trick.
I'm implementing a dialog view, using AutoViews that are available in MVVMCross.AutoView.
Does any one know if it is possible to create dinamic sections. e.g. Something like being able to bind the Elements list of a Section, to a notifiable list in the ViewModel.
What you are looking for is not implemented currently within the Dialog part of AutoViews - just as it's not implemented in the source MonoTouch.Dialog or MonoDroid.Dialog
Adding INotifyCollectionChanged-aware sections to Dialog would definitely be possible, but it would require some skill and time to merge it into the Dialog core code.
If your list (ObservableCollection) is standalone, however - if it doesn't rely on sitting within a larger Dialog - then the list part of AutoViews should work OK for you.
You can see a list AutoView implemented in https://github.com/slodge/MvvmCross/blob/vnext/Sample%20-%20CustomerManagement/CustomerManagement%20-%20AutoViews/CustomerManagement/ViewModels/CustomerListViewModel.cs - this works off of an IObservableCollection and seems to update as you add/remove customers.
Note that AutoViews is still very 'young' - and it'll remain so until we start getting a few more platforms working - there are people working on WP and WinRT Dialog implementations, but these are 'spare time' projects and the people are busy!