Image without content description using Compose - accessibility

In my app that only uses Jetpack Compose, I want show an image without a content description. The goal of this element is specifically to show how not to do it; I want TalkBack to pronounce it as 'unlabeled' and any other AccessibilityService to handle it like that service handles it. Therefore, the service needs to receive an AccessibilityNodeInfo node with as class name "android.widget.ImageView" and contentDescription = null
Google tried their very best to prevent developers from creating a bad experience for visually impaired and succeeded. An image without a content description is removed from the semantics tree and is not read out; an AccessibilitityService will not be aware of it:
Image(
painter = painter,
contentDescription = null
)
Mimicking Image() and manually setting the Role to Image and not setting a description also removes it from the semantics tree:
Layout(
{},
modifier
.semantics { this.role = Role.Image }
.paint(painter)
) { _, constraints ->
layout(constraints.minWidth, constraints.minHeight) {}
}
Also when I use an xml layout containing an ImageView without a content description, this does not show as an element to any accessibility services.
Compose implements MyNodeProvider, an AccessibilityNodeProvider which is Androids bridge between an accessibility service and an app. This is the class that populates the AccessibilityNodeInfo with a description or removes it from the tree. Because this is private, this cannot be altered.
Is it possible with Compose for an element to show up as "android.widget.ImageView" with contentDescription = null?

If you want TalkBack to pronounce it as 'unlabeled', wouldn't setting the content description to 'unlabeled' be the way to go?
The question is not much clear, but if you want the content to be identified as nothing special or interactive with TalkBack, you could always set the contentDescription to null.
BASED ON THE UPDATE
You can simply use an AndroidView for this purpose
AndroidView(
factory = {
ImageView(...) // Populate it here
}
)
This is in itself a Composable function so you can literally just swap out your Image Composable with this and it'll work.
Take The Migration Codelab to get full insights on API usage.

Related

Visual Studio SDK - How to add a margin glyph on command invoked?

How can I modify this sample: https://msdn.microsoft.com/en-us/library/ee361745.aspx to have glyphs added to the margin when a button I added is clicked?
I have a button which creates a special kind of breakpoint. I would like this kind to be recognized by my own margin glyph. So I wrote the GetTags method in my Tagger class as follows:
IEnumerable<ITagSpan<MyBreakpointTag>> ITagger<MyBreakpointTag>.GetTags(NormalizedSnapshotSpanCollection spans)
{
if (BreakpointManager != null)
{
DTE2 ide = ServiceProvider.GlobalProvider.GetService(typeof(DTE)) as DTE2;
Document document = ide.ActiveDocument;
foreach (SnapshotSpan span in spans)
{
ITextSnapshot textSnapshot = span.Snapshot;
foreach (ITextSnapshotLine textSnapshotLine in textSnapshot.Lines)
{
if (BreakpointManager.IsMyBreakpointAt(document.FullName, textSnapshotLine.LineNumber + 1))
{
yield return new TagSpan<MyBreakpointTag>(new SnapshotSpan(textSnapshotLine.Start, 1),
new MyBreakpointTag());
}
}
}
}
}
However, glyphs are added after moving the cursor to a different line of code or making changes to the code. What do I have to do to have glyphs added right after the button is clicked?
GetTags is called by the editor whenever a layout happens, but the editor won't call it for any random reason. (Think: how would it know when to call you?) You need to raise the TagsChanged event from your tagger to say the tags for a given span changed, and then it'll call GetTags again to refresh.
As an unrelated piece of advice: you shouldn't be using DTE.ActiveDocument in your GetTags for a few reasons:
GetTags should be as fast as possible...calling DTE methods are rarely fast.
Imagine you have two files open, and GetTags is called for the non-active file. That would have both files looking at the same filename which is probably bad. There's code here that shows how to fetch the file name from an ITextBuffer.
This is copied from my answer here. Basically, changing from using ITaggerProvider to IViewTaggerProvider allowed me to redraw the glyphs. I used the Implementing a Brace Matching Tagger Provider section in Walkthrough: Displaying Matching Braces example to make these changes.
Using the IViewTaggerProvider, you can then call
TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(
new SnapshotSpan(
SourceBuffer.CurrentSnapshot,
0,
SourceBuffer.CurrentSnapshot.Length)));
in your functions to explicitly call GetTags and go over the spans in the current snapshot.

How to handle first tab size on formatting?

I create an extension, that format vs editor tabs in custom ways, using ITextParagraphPropertiesFactoryService class. Everything works just fine, expect the fact, that when user enter new line, ITextParagraphPropertiesFactoryService doesnt affect to the new line
For simplifying the problem, I create a new MEF project, add a format provider like this
[Export(typeof(ITextParagraphPropertiesFactoryService))]
[ContentType("text")]
[TextViewRole(PredefinedTextViewRoles.Document)]
internal class ElasticTabstopsProvider : ITextParagraphPropertiesFactoryService
{
/// <summary>
/// Creates an ElasticTabstopsFormatters for
/// the provided configuration.
/// </summary>
public TextParagraphProperties Create(IFormattedLineSource formattedLineSource, TextFormattingRunProperties textProperties,
IMappingSpan line, IMappingPoint lineStart, int lineSegment)
{
return new TextFormattingParagraphProperties(textProperties, 1);
}
}
And it changes all tabs width from my editor to 1. Great! This is what I want. But now when I press Enter(new line) new cursor is set under Main, however I expect tab widths to be 1.
After I start typing it goes to expected position.
The question is, how can I set new line empty line tab size?
I try to override ISmartIndentProvider, but seems vs ignore that value.
Debuger stops on breakpoint in method
int? GetDesiredIndentation(ITextSnapshotLine currentLine)
of ISmartIndent, but indent stays the same no matter what value I return...
There are at least two reasons why your ISmartIndentProvider's indent is being ignored:
First, there are lots of places with the current C# and VB language services where we explicitly set the caret position in response to certain keypresses. Enter is one of them. It's quite possible that in your scenario, we're explicitly setting the position. Short of disabling smart indenting in Tools > Options, there's nothing you can do to override that. Since you said you're getting a debugger hit in your ISmartIndentProvider, that's probably the issue here.
Second, if you're trying to define a ISmartIndentProvider for content type "text", yours won't get called if there is a language-specific provider. There's also another provider for "text" already (which calls the shimmed old language services) which might win over yours anyways.
To be honest, if you're trying to do something fancy where you don't want automatic indenting, then you really should just turn it off to ensure it's not getting in your way.

How to add default custom action to dashlet's title bar in Alfresco Share

Since some days ago I'm struggling to find out the best way to add a custom action in every dashlet's title bar by default.
At this stage, I know the actions are set up as a widget in every dashlet's webscript. For example, in docsummary.get.js:
var dashletTitleBarActions = {
id : "DashletTitleBarActions",
name : "Alfresco.widget.DashletTitleBarActions",
useMessages : false,
options : {
actions: [
{
cssClass: "help",
bubbleOnClick:
{
message: msg.get("dashlet.help")
},
tooltip: msg.get("dashlet.help.tooltip")
}
]
}
};
model.widgets = [docSummary, dashletResizer, dashletTitleBarActions];
Then, the widget is instanciated in when the page is rendered.
I have figured out the next approaches:
Augment the "actions" array of every widget instance with the action I need in a custom JS snippet, every time the page is rendered. I have performed some tests without success using techniques like this: http://acidmartin.wordpress.com/2012/03/19/getting-instance-names-of-a-javascript-object/
Modify the prototype of Alfresco.widget.DashletTitleBarActions by adding my custom action. I believe it doesn't work either as the "actions" object is always overridden when the widget is instantiated, as you can see in the code above pasted.
Create an extension module for every dashlet's webscript which adds the custom action for every Alfresco.widget.DashletTitleBarActions widget definition, similarly as Dave Drapper explains in his post http://blogs.alfresco.com/wp/ddraper/2012/05/22/customizing-share-javascript-widget-instantiation-part-1/
Get every dashlet div container and add the action required directly manipulating the DOM once the page is ready. It should work but is something I consider slightly dirty and inconsistent, hence I would like to avoid it.
Could anyone imagine a better and feasible solution??
Let's start with adding an action to a single existing dashlet. As you suggest in (3) you can define an extensibility module to change the behaviour of the dashlet by intercepting and modifying its model.
Creating an extensibility module is well covered on the blog article and follow-up posts, but the trick here is to provide a controller JavaScript extension which locates the DashletTitleBarActions widget and adds your action to it, e.g.
if (model.widgets)
{
for (var i = 0; i < model.widgets.length; i++)
{
var widget = model.widgets[i];
if (widget.id == "DashletTitleBarActions")
{
widget.actions.push({...})
}
}
}
What you put in the object literal depends on how your action is implemented. If you require some client-side behaviour (rather than say, a static link) then you will also need to bind that in using a CustomEvent - see the RSS Feed dashlet org/alfresco/components/dashlets/rssfeed.get.html.ftl for an example.
The down-side of an extensibility module is that you will need to define an explicit extension JS file for each dashlet. You could easily put the code above in a central file and then include it in each dashlet extension where it is needed, e.g.
<import resource="classpath:alfresco/site-webscripts/org/myco/utils/dashlet.utils.js">
I would take the road number 2 here.
The definition of this widget is in share.js file ({share.context}/js/share.js). For Alfresco 4.2, DashletTitleBarActions is defined at around line 1700. In the onReady handler of the widget, there's a loop that processes the actions.
// Reverse the order of the arrays so that the first entry is furthest to the left...
this.options.actions.reverse();
// Iterate through the array of actions creating a node for each one...
for (var i = 0; i < this.options.actions.length; i++)
{
As you can see, it reverses the order of actions parameter, and then adds starts to loop the actions. So depending if you want your action to be the first or last, you could probably edit this file and add your custom action:
myAction = {
"cssClass": "customCSS"
, "tooltip": this.msg("slingshot.messages.generic.tooltip")
, "eventOnClick": ...
...
}
this.options.actions.push(myAction);
// now move on with the rest of the loop
for (...)
Of course, that requires overwriting shares' own js file, and not extending it. If you can't do that, you would then have to include a custom JS file on each page where share.js is also included and make sure it's executed after share.js but before any of the widgets are ready, and overwrite the onReady method of the widget itself so that it does this.

flex mobile project : memory management

I have developed my first flex mobile application which is of TabbedViewNavigatorApplication. Application is working fine but when I test the application in "profile handler", memory usage goes on increasing as I navigate through the application. When I came to know that, I have to remove all the added eventlisteners and I have to nullify the objects which are no longer needed. When I switch between tabs , tabs are initialising again and again.
I dont know where can I remove the eventlisteners. I mean, I have written functions for each eventlisteners . Do I need to remove eventlistener when control goes to the function definition.
I have written sample code
var more:Image = new Image();
more.width = 70;
more.height=29;
more.x=10;
more.y=276;
more.source = "Assets/more button.png";
more.addEventListener(MouseEvent.CLICK, MORE_clickHandler);
mainGroup.addElement(more);
private function MORE_clickHandler(e:MouseEvent):void {
// Do I need to remove the eventlistener here
}
Also , do I need to explicitly nullify the object of Image class which I created or garbage collector will handle it. If I need to explicitly nullify it, where to do this.
Thanks
Garbage collection is an important part of any language, especially on mobile. Since mobile devices are a lot more limited than say our desktop counterparts, you need to be very careful what is being created/stored to memory. My motto is, if you don't see it, you shouldn't keep it. You can destroy views but keep their state using a view model.
To remove a view, you need to first remove it from the display list (removeElement(yourObject)), remove all event listeners, and nullify any referencing variable. If any variable still has a reference to it, it won't get garbage collected.
I recommend you read up a bit more on garbage collection as well as some neat tricks like pooling and virtualization (item renderers in a list).
You can setup an event listerener with a weak reference.
This implies that when the only reference to your object is the listener, the object itself can still be garbage collected and the listener will not keep it in memory.
The following will do the trick :
more.addEventListener(MouseEvent.CLICK, MORE_clickHandler,false, 0, true);
Another option would be to subclass the image class and let it implement an IDisposable interface, which would force you to implement a dispose() method.
Some handy resources:
http://www.intriguemedia.net/2007/09/24/when-to-use-weak-references
http://gskinner.com/blog/archives/2006/07/as3_weakly_refe.html
cheers

Editing A Library Symbol From ActionScript

In the Flash authoring environment I can edit a library symbol and all on-stage instances based upon it reflect the changes. How can I do the same thing in ActionScript? There seems to be no way to address a library symbol.
For example:
Inside Flash CS3, I have created a Square.swf file that has 100 instances of the library symbol Square.
Now, Square.swf is loaded into another file BlueSquare.swf and I want to change the Square symbol into a blue square so that all instances of Square become blue.
How do I do this using Actionscript?
Thanks for the help.
What's in a clip's library symbol is the author-time definition of that object - you can't change it at runtime. Instead the normal approach would be to dynamically change the contents (not definitions) of the clips you want to change, which can be done in various ways, but all the good ways of doing that involve making the dynamically-changing clip understand how to update its appearance. So you need to be able to re-author the changing clips to suit your needs.
If you're loading in an animation that somebody else made, and trying to go through and replace all instances of object A with object B, the only way to achieve that is to traverse through the content's display list looking for A, and when you find one, remove its children and replace them with the the contents of a B. Mind you, for animations that may not really solve your problem, since animations normally add and remove clips frequently, so at any given point you could replace all the "hand" clips with "hand2", but then a frame later new "hand" clips might come into existence. But short of opening up the SWF and changing the binary data inside, there's no other way to dynamically change all of a given object to something else unless the object knows how to change its contents.
If it is only about making sure that the square you are attaching is blue you could use the colorTransform to change its appearance:
var someSquare:Square = new Square();
someSquare.transform.colorTransform = new ColorTransform(0,0,0,1,0x00,0x00,0xff,0x00 );
addChild( someSquare );
Of course this does not change the color of all instances that you have already attached.
If you really wanted to change the actual SWF symbol in Actionscript the only way I see is to parse the swf with as3swf ( https://github.com/claus/as3swf/wiki ), find the shape tag of the symbol, change it and then load the ByteArray that contains the swf via loader.loadBytes() - but that's admittedly quite a complicated way and you can achieve the same result by simply putting some colorizing code into the shape symbol itself and then trigger the color change via an Event that is broadcasted by your main app.
Of course, if you make custom component, when you change it changes will appear on all instances of that component/class. Here's the example: http://livedocs.adobe.com/flex/3/html/intro_3.html
On the other hand, if you use modules whey pretty much do the same as swf-s you used in Flash, when you rebuild-recompile them changes will reflect on your main application which uses them. Here's th eexample for modules: http://blog.flexexamples.com/2007/08/06/building-a-simple-flex-module/
So MXML/AS component/class are your "symbols" which you can create or drop on stage on fly.
Modules are "movies" you can load and they run on their own with possibility to communicate to main movie.
The closest way of achieving this is to use Bitmaps. If you update the bitmapData they display, they will all update automatically.
However this approach is not good at all. You should maintain application state separately in an object model, and have the visualisation update, if the state changes.
What you want to do, is to misuse a feature for changing graphic appearence at design time, to change application state at runtime. In generally, ideas like these can be thought off as bad.
For example if you take the time to separate the state model and the visualisation layer, it will become fairly easy to save the game state on a server or to synchronize it with other clients to achieve multiuser features.
greetz
back2dos
If you are trying to build an Avatar and user can customize your Avatar parts e.g. hands, legs, face etc. and you want all these assets to be kept in separate swf file, that is pretty straightforward. You keep all the assets, in separate swf or one large swf file and load them at runtime. Now, maintain your Avatar object instance and place the child objects, which are chosen by the user.
You can create inside your class a static List with references all the created instances and then apply a change with static methods. For example:
package
{
import flash.display.MovieClip;
import flash.geom.ColorTransform;
public class Square extends MovieClip
{
public static var instances:Array = new Array();
public function Square():void
{
Square.instances.push(this); // This is the trick. Every time a square is created, it's inserted in the static list.
}
// This property gets the color of the current object (that will be the same of all others because the setter defined below).
public function get color():ColorTransform
{
return this.transform.colorTransform;
}
public function set color(arg:ColorTransform):void
{
// Sets the color transform of all Square instances created.
for each(var sqr:Square in Square.instances)
{
sqr.transform.colorTransform = arg;
}
}
}
}

Resources