Android supports a number of different text input types. If you create a text field in which someone is intended to enter a phone number, address, email address, you can set the text input type on the text field to have the keyboard automatically restrict what characters it presents to the user.
<EditText android:inputType="phone" />
I was working on something for which I needed to ensure that the user selected an emoji. Unfortunately, there’s not an input type to restrict a user to emoji. How do I ensure taht the user can only enter emoji? I could implement my own keyboard that only displays emoji, but for the time being I do not what to implement such a thing for the application that I’m building. There are a number of different possible solutions for this. The one I chose was to make a custom text input field and an InputFilter for it.
Making a custom field may sound like a lot of work, but it isn’t. The custom field itself is primary declarations with only a single line of initialization code that applies the filter. The real work is done in the filter itself. For a custom InputFilter, make a class that derives from InputFilter. There is a single method on the class to define named filter.
The filter method receives the text sequence that is going to be assigned to the text field. If we want to allow the field value to be assigned to the text field, the function can return null. If there is a character of which I don’t approve, I’ll return an empty string which will clear the text field. If I wanted to replace a character, I could return a string in which I had performed the replacement. The value returned by this function will be applied to the text field.
In my implementation for this function, I step through each character in the string (passed as a CharSequence, a String is a type of CharSequence) and check the class of each character. If the character is not of acceptable class, then I return an empty string to clear the text field. For your purposes, you may want to strip characters out and return the resulting string.
The function Character::getType will return the character type or class. To ensure that the character is an emoji, I check to see if the type value equals to Character::SURROGATE or Character::OTHER_SYMBOL.
private class EmojiFilter : InputFilter {
override fun filter(
source: CharSequence?,
start: Int,
end: Int,
dest: Spanned?,
dstart: Int,
dend: Int
): CharSequence? {
for( i in start .. end-1) {
var type = Character.getType(source!!.get(i)).toByte()
if(type != Character.SURROGATE && type != Character.OTHER_SYMBOL) {
return "xx";
}
}
return null;
}
}
Now that the filter class is defined, I can create my custom text field. It has next to no code within it.
And that’s it. While Android doesn’t give the option of showing only the Emoji characters, with this in place I’m assured that a user will only be able to enter Emoji characters.
I recently worked on a project that made use of Phidgets hardware. Phidgets has many offers for interfacing hardware sensors to a computer using USB. Provided that the drive is installed, using the service is pretty straight forward. They have software components available for a variety of languages and operating systems. For the project that I was working on, a computer would have multiple Phidget RFID readers. When there are multiple instances of hardware on a system, a specific instance can be addressed through it’s serial number. On this project, the serial numbers were stored in a configuration file. For the single machine on which this project was deployed, that was fine. Once that was a success the client wanted the software deployed to another 7 machines.
The most direct strategy for this would be to make a configuration file for each machine that had its specific serial numbers in it. I did this temporarily, but I am not a fan of having differences in deployment files. A simple mistake could result in the wrong configuration being deployed and a non-working software system. Deployments would be frequent because users were interacting with the software during this phase of development. An unexpected problem we encountered was someone disconnected hardware from one computer and moved it to another. Why they decided to perform this hardware swap is not known to me. But it resulted in two machines sensors that were no longer responsive.
After a little digging I found a much better solution.
For some reason the Phidgets code examples that I encounter don’t mention this, but it is also possible to get notification of a Phidgets device being connected or disconnected from the computer and the serial number of the device being references. I used a .Net environment for my development, but this concept is applicable in other languages too. I’ll be using .Net in my code examples.
In the .Net environment, Phidget’s offers a class named Manager in their SDK. The Manager class when instantiated raises Attached and Detached events each time an item of hardware is connected or disconnected from the system. If the class is instantiated after hardware has already been connected, it will raise Attached events for each item of hardware that is already there. The event argument object contains a member of the class Phidget that among other data contains the serial number of the item found and what type of hardware it is. For the application I was asked to update, I was only interested in the RFID reader hardware. I had the code ignore any Phidget of any other type. While it is unlikely the client would randomly connect such hardware to the machines running the solution, for the sake of code reuse it is better to have such protection in the application.
Let’s make an application that will list the RFID readers and the RFID readers detected by each tag. I’m writing this in WPF. Not shown here is some of the typical code you might find in such a project such as a ViewModel base class. In my sample project, I wrapped the Phidgets Manager class in another class that will also keep a list of the Phidget object instances that it has found. An abbreviated version of the class follows. The Phidget’s Manager class will start raising Attached and Detached events once its Open() method has been called. If there is already hardware attached, expect events to be raised immediately.
public partial class PhidgetsManager:IDisposable
{
Manager _manager;
List<Phidget> _phidgetList = new List<Phidget>();
public PhidgetsManager()
{
_manager = new Manager();
_manager.Attach += _manager_Attach;
_manager.Detach += _manager_Detach;
}
private void _manager_Detach(object sender, Phidget22.Events.ManagerDetachEventArgs e)
{
_phidgetList.Remove(e.Channel);
OnPhidgetDetached(e.Channel);
}
private void _manager_Attach(object sender, Phidget22.Events.ManagerAttachEventArgs e)
{
_phidgetList.Add(e.Channel);
OnPhidgetAttached(e.Channel);
}
public enum Action
{
Connected,
Disconnected
}
public class PhidgetsActionEventArgs
{
public Phidget Phidget { get; internal set; }
public Action Action { get; internal set; }
}
public delegate void PhidgetsActionEvent(object sender, PhidgetsActionEventArgs args);
public event PhidgetsActionEvent DeviceAttached;
public event PhidgetsActionEvent DeviceDetached;
protected void OnPhidgetAttached(Phidget p)
{
if (DeviceAttached != null)
{
var arg = new PhidgetsActionEventArgs()
{
Action = Action.Connected,
Phidget = p
};
DeviceAttached(this, arg);
}
}
protected void OnPhidgetDetached(Phidget p)
{
if (DeviceDetached != null)
{
var arg = new PhidgetsActionEventArgs()
{
Action = Action.Connected,
Phidget = p
};
DeviceDetached(this, arg);
}
}
}
In my MainViewModel I only wanted to capture the RFID readers. It has its own list for maintaining these. When a device of the right type is found, I create anew RFID number and assign its DeviceSerialNumber. When the class’s Open() method is called, it will attach to the correct hardware since the serial number has been set. The RFID instance is added to my list. My list uses a wrapper class that exposes the device serial number and the current RFID tag that the device sees. This is exposed through a ViewModel object so that the UI will automatically update.
public class RFIDReaderViewModel: ViewModelBase, IDisposable
{
RFID _reader;
public RFIDReaderViewModel(Phidget phidget)
{
if(phidget == null)
{
throw new ArgumentNullException("phidget");
}
if(phidget.ChannelClass != ChannelClass.RFID)
{
throw new ArgumentException($"Phidget must be an RFID Reader. The received item was a {phidget.ChannelClassName}");
}
this.Reader = new RFID();
this.Reader.DeviceSerialNumber = phidget.DeviceSerialNumber;
this.Reader.Tag += Reader_Tag;
this.Reader.TagLost += Reader_TagLost;
this.Reader.Open();
}
private void Reader_TagLost(object sender, Phidget22.Events.RFIDTagLostEventArgs e)
{
Dispatcher.CurrentDispatcher.Invoke(() =>
{
CurrentTag = String.Empty;
});
}
private void Reader_Tag(object sender, Phidget22.Events.RFIDTagEventArgs e)
{
Dispatcher.CurrentDispatcher.Invoke(() =>
{
CurrentTag = e.Tag;
});
}
public RFID Reader
{
get { return _reader; }
set { SetValueIfChanged(() => Reader, () => _reader, value); }
}
String _currentTag;
public String CurrentTag
{
get { return _currentTag; }
set { SetValueIfChanged(() => CurrentTag, ()=>_currentTag, value); }
}
public void Dispose()
{
try
{
this.Reader.Close();
}
catch (Exception exc)
{
}
}
}
All that’s left is the XAML. In the XAML for now, I’m only interested in listing the serial numbers and the tag strings.
With that in place, now when I run the project, I get live updates of RFID tags coming into or out of range of each of the readers connected.
If you try to run this though, you may encounter a problem. The RFID readers (as the name implies) use radio frequencies for their operation. If they are close to each other, they may interact and interfere with each other. Don’t worry, this doesn’t mean that you can’t use them in close proximity. In my next entry I’ll show how to deal with RFID readers that are close to each other and mitigate interference through software.