Android Accessibility Service Customization For KeyPress Event

Accessibility services are a feature of the Android framework designed to provide alternative navigation feedback to the user on behalf of applications installed on Android devices.

It runs in the background and receives callbacks from the system when accessibility event is fired. Of course when accessibility is enabled on the device.

Examples of common accessibility services

  • Voice Assistance.
  • Switch-Access: Allows Android users with mobility limitations to interact with devices using one or more switches.
  • Talkback: A screen reader commonly used by visually impaired or blind users.

Sometimes there are unique requirements. For instance, let’s say, on pressing “Caps Lock” instead of relying on the talkback (that speaks out, “Caps Lock On” & “Caps Lock Off”) we want to play an audio file instead. This is more relevant when the user does not know “English” & hence the default talkback, which is in English is not going to work. The solution is to use an audio file in the localized language.

Creating an accessibility service

We can build our own accessibility service as per application requirements to make it more accessible.

Let’s take an example of Typing Tutor app, where we may need to override hardware keyboard event using accessibility service.

In this example, we are going to override the windows key press event, to start your app’s home menu, instead of device start menu (By default on android it opens Google assistant).

Steps

  • To Register your accessibility service, create a service class which receives accessibility events
public class MyAccessibilityService extends AccessibilityService {
...
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
         // your code...
    }

    @Override
    public void onInterrupt() {
    }

...
}
  • Like any other service, you also have to register it in the manifest file. Remember to specify that it handles the android.accessibility intent, so that the service is called when applications fire an AccessibilityEvent.
<service android:name=".MyAccessibilityService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
. . .
</service>

Configuration Service

An accessibility service can be configured to receive specific types of accessibility events,  In our case, it should be keyboardEvent. 

We can also add a filter like it can listen only to the specific app (package name), specific time duration, can work only with particular activity etc.

there are two ways to configure service event settings:

  1. Via meta-data entry in the manifest file.
  2. Programmatically, by calling setServiceInfo(AccessibilityServiceInfo)

Example for XML configuration:

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackSpoken"
    android:notificationTimeout="0"
    android:canRequestFilterKeyEvents="true"
    android:accessibilityFlags="flagRequestFilterKeyEvents"
    android:description="@string/message_accessibility_service_details"
    android:packageNames="com.test.accessebility" />

Here I used android:canRequestFilterKeyEvents=”true” & android:accessibilityFlag=”flagRequestFilterKeyEvents” to get key events from the system. Also, have to override the onKeyEvent() method inside our service class

@Override
protected boolean onKeyEvent(KeyEvent event) {
    return super.onKeyEvent(event)
}

That’s it. We are done with the service configuration. Don’t forget to add the below permission in your manifest file.

<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"/>

Now to get this event to our Activity class, we are going to user local broadcast manager. It’s an android component which allows you to send or receive Android system or application events.

@Override
protected boolean onKeyEvent(KeyEvent event) {

//handle keyevent for widnows key
if((keyCode == KeyEvent.KEYCODE_META_LEFT || keyCode == KeyEvent.KEYCODE_META_RIGHT)) {
       //Send broadcast intent to main activity. 
       //On the main activity you can take any desired action.
    }
    return super.onKeyEvent(event)
}

Then register that local broadcast on your activity class. By this activity will get notified whenever an event occurs. Now you can write your own action on it.

You are done!!

Advertisements

Getting started with Android and Kotlin

With Google IO 2017, Google announced Kotlin as the officially supported language for Android.

Kotlin will be now shipped with Android Studio working out of the box, starting with version 3.0. No extra installations needed. No more incompatible plugins. All thanks to close collaboration between JetBrains and Google.

Why Kotlin?

Most importantly, it was because we think Kotlin is a great language that will make writing Android apps easier and more enjoyable.

Kotlin is also a great match for the existing Android ecosystem. It is 100% compatible with the Java programming language. We can add as little or as much Kotlin into our existing codebase as we want and mix the two languages freely within the same project.

A Quick Tour

here is a quick tour of some of the particularly appealing aspects of Kotlin:

1.Null Safety

One of the Kotlin’s best features is null safety. The Kotlin compiler enforces that variables that can hold null values are explicitly declared – thus no more NullPointerExceptions at runtime!

var neverNull: String = "something"
var mightBeNull: String? = null // "?" indicates this can be null
if (neverNull.length > 0) {  // This is OK…
   …
}
if (mightBeNull.length > 0) { // Compiler catches this error for us
   …
}

2. Extension Functions

Extension functions are functions that, as the name implies, help us to extend the functionality of classes without having to touch their code.

In other words, the extension functions in Kotlin allow us to extend the functionality of a class by adding new functions. The class doesn’t have to belongs to us (could it be a third party library) and also without requiring us to inherit the class.

Really? without inheriting the class.

Yes! It’s possible in Kotlin.

Let’s stop talking, will show how it is possible.

Taking a very simple example to understand. Suppose we need to load the image using the Picasso library:

//Using Java
Picasso.with(imageView.context).load(url).into(imageView)
//Creating extension function with Kotlin
fun ImageView.loadUrl(url: String) {
    Picasso.with(context).load(url).into(this)
}

//calling extension function
imageView.loadUrl(url)

3. Default Argument

Function parameters can have default values, which are used when a corresponding argument is omitted. This allows for a reduced number of overloads compared to other languages.

4. Named Argument

Function parameters can be named when calling functions. This is very convenient when a function has a high number of parameters or default ones.

fun reformat(str: String,
            normalizeCase: Boolean = true,
            upperCaseFirstLetter: Boolean = true,
            divideByCamelHumps: Boolean = false,
            wordSeparator: Char = ' ') {

            ...
}

we could call this using default arguments

reformat("kotlin")

5. Kotlin is concise

One of the main advantages of Kotlin is its concision. We get more functionality with less code. And the less code we write, the fewer mistakes we make. It’s pretty straightforward.

//Data model class written in java
public class Person {

private String id;
private String name;

public Person(String id, String name) {
this.id = id;
this.name = name;
}

public String getId() {return id;}

public void setId(String id) {
this.id = id;
}

public String getName() {return name;}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "Person{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}

@Override
public boolean equals(Object o) {
return super.equals(o);
}

@Override
public int hashCode() {
return super.hashCode();
}
}
//An equivalent class written in Kotlin.
data class Person(var id: String,var name: String)

Yes, we’ll automatically get needed getters, setters, equals(), hashcode(), toString() and copy() functions for our data class! Of course, we can easily override these functions, but in most cases it’s enough just to declare the class and its properties.

6. Remember filtering lists with for loops?

Thanks to the functional approach to collections, we can also reduce all the complex, multiline instructions to only one line of code.

//How collections were handled in Java
void processList(List<Integer> list) {
  List<> stringList = new ArrayList<>();
    for (Integer i : list) {
      if (i % 2 == 0) {
        stringList.add(i.toString());
      }
    }
}
//How Kotlin handles collections
fun processList(list: List<>) {
  val stringList = list.filter { it % 2 == 0 }. map { it.toString() }
}

7. No More findViewById

We all Android Developers have been bored writing findViewById to bind the views. Kotlin Team realized it and they gave us Android Extensions.

Kotlin Android Extensions are another Kotlin plugin that is included in the regular one. It eliminates the need of findViewById in our code.

Go to your gradle module file and add

apply plugin: 'kotlin-android-extensions'

That’s it! The setup is done! We can directly get the view in our Activity by the id specified in the layout.

Under the hood: Internally the compiler creates a small hidden cache function which callsfindViewById for every view on that Activity or Fragment giving us the synthetic property to use the view.

8. Control Flow

If Expression: In Kotlin, if is an expression, i.e. it returns a value. Therefore there is no ternary operator (condition ? then : else), because ordinary if works fine in this role.

// Traditional usage
var max = a
if(a < b) max = b
// With else
var max Int
if(a > b) {
   max = a
} else {
   max = b
}   

// As expression
val = if(a > b) a else b

When Expression: when replaces the switch operator of C-like languages. In the simplest form it looks like this.

when(x) {
     1 -> print("x == 1")
     2 -> print("x == 2")
     else -> { // Note the block
         print("x is neither 1 nor 2")
     }
}

when matches its argument against all branches sequentially until some branch condition is satisfied. when can be used either as an expression or as a statement. If it is used as an expression, the value of the satisfied branch becomes the value of the overall expression.

Some of my favorite Kotlin features:

  1. Replacing simple if/else if/else blocks with when
  2. Extension function
  3. No more view binding
  4. Functions in one line
  5. Beautifying even the ugliest click handlers
  6. Reducing the need for`if (whatever != null)`

Getting Started

If you want to get started with Kotlin, you can start playing with code online immediately here. Just hit the green triangle to compile and run.

Happy Coding 🙂

Create multiple flavors of an Android app using gradle script

I’ve been asked sometimes on how to work with different hosts, different icons, or even different package names, depending on different versions of the same app.

There are lot of reasons to do this and one easy way to go: Product Flavors.

Product Flavor is a very powerful feature available in the Android gradle plugin that allows us to manage different “flavors” of an application.

In this blog, we are going to learn, how to design and build a single application with multiple flavors, which can be pushed to the Play Store and deployed on the same device simultaneously.

You can use the productFlavors closure of your app/build.gradle file to define different variants of your product.


productFlavors {

    ....

    free {
        applicationId 'com.example.app.free'
    }

    paid {
        applicationId 'com.example.app.paid'
    }

}

In addition to flavors, there is another very important concept regarding building android apps, called “build types”.


buildTypes {

        release {

            minifyEnabled false
            debuggable false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

            signingConfig signingConfigs.release

        }

        debug {

            minifyEnabled false
            debuggable true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

            applicationIdSuffix ".debug"

        }
}

Once the changes have been made on app/build.gradle file, a yellow warning bar will appear across the top of the editor indicating that the changes to the Gradle build file need to be synchronized with the rest of the project. Click on the Sync Now link located in the warning panel to perform the synchronization.

screen-shot-2016-11-09-at-11-56-00-am

Before proceeding to the next step, open the Build Variants tool window either using the quick access menu located in the status bar in the bottom left hand corner of the Android Studio main window or using the Build Variant tool window bar. Once loaded, clicking in the Build Variant cell for the app module should now list the four build variants:

Providing Alternate Resources

Now we’re going to start customizing the application per flavor, starting with resources. Initially the project structure looks like below:

In this structure, main is your default source directory (i.e. the “unflavored” source). So, where you would put your flavor customizations? in a flavored directory, that is.

Let’s say we want to provide a different launcher icon for both Free and Paid Flavor, so under the src folder we are actually going to create two folder/directory named free and paid. Then add different launcher icon for all flavors, also remember file name & directory structure should be same as main folder.

 

 

Flavor Specific Dependency

Adding “flavorCompile” syntax in dependency section of app level build.gradle adds the dependency for that particular flavor. Lets assume the app uses Google Admob for the ads.

 
dependencies {

    ....

    compile 'com.google.android.gms:play-services-ads:7.8.0' 

}

The disadvantage of this setup is that it will always pull in the admob library, including the premium version of the app, even though it doesn’t need the code at all!

In order to satisfy your paying customers and only pull the admob dependency for the free version of the app, change the build.gradle to this:

 
dependencies {

    ....

    freeCompile 'com.google.android.gms:play-services-ads:7.8.0' 

}

This tells gradle, that this dependency is only required for the productFlavor “free”. This also help to reduce .apk file size.

That’s it! You won’t have to do anything more! Gradle will automatically pull the dependencies for the selected productFlavors only.

You can also generate the .apk file using terminal by following command:

Syntax:-

 ./gradlew assemble(ProductFlavor)(buildType) 

eg:-

 ./gradlew assemblefreeDebug 

the complete source for the sample app built for this article is available on GitHub, and can be used by all.

There is a standard way of doing it but just like me I think lot of other devs are not aware of it. So I thought of putting this down concisely somewhere.

Happy coding :-).