Category: Android Library

And the Winner for Best Screenplay in an Android Bug Report is …

“People are implementing IPv6 only networks with DHCPv6. Please implement RFC 3315.” by someone named Tyler.

Comment

TextUtils.isDigitsOnly Returns True if Given an Empty String

I happened across this problem while using the Android SDK’s TextUtils.isDigitsOnly() method recently.

This is the body of that method from the API 27 source:

    public static boolean isDigitsOnly(CharSequence str) {
        final int len = str.length();
        for (int cp, i = 0; i < len; i += Character.charCount(cp)) {
            cp = Character.codePointAt(str, i);
            if (!Character.isDigit(cp)) {
                return false;
            }
        }
        return true;
    }

Someone filed a bug report against it in January 2012. It seems no progress toward a fix has been made.

The app I’m coding is in Kotlin, and my first thought was to try to create my own local fix by creating my own local TextUtils.isDigitsOnly implementation in an extension function.

But this is not (yet) possible for a static method whose original definition is in a Java class (as opposed to a Kotlin class). Someone has filed a feature request to make it possible though. (It seems like a sensible request to me because there’s an asymmetry between Kotlin and Java with respect to extension functions: with Kotlin-defined classes you can reimplement both instance and companion object methods, but with Java-defined classes you can only reimplement instance methods.)

Anyway, in the mean time I replaced this expression:

TextUtils.isDigitsOnly(myString)

with this expression:

!TextUtils.isEmpty(myString) && TextUtils.isDigitsOnly(myString)
Comment

To Change the Option Menu’s Text Color and Typeface, I Got Rid of the Whole Thing

For a Halloween mapping app I was working on recently, I wanted to change the color and typeface of items in the standard options menu.

After trying some obvious things, like experimenting with text/color/font related attributes on the ‘item’ tag and monkeying around with the app’s theme, I found that I do not know how to do this.

So, I looked at this, this, this, and this. But, I never quite managed to change both the color and the typeface on the individual menu items. (Maybe I could have created a custom class that merges the features of a ForegroundColorSpan and a TypefaceSpan and a SpannableString or something, but I ran out of patience.) It started to look like more work than I wanted to do. And I’m not a big fan of the options menu anyway.

So I gave up on the options menu and started to look for something else. Eventually, I found Nightonke’s Boom Menu. Compared to most free android libraries hosted on GitHub, Boom Menu is awesome. Changing the text color and typeface are EASY. And the documentation is solid.

It was easy to change a Boom Menu button’s text color and typeface. I read the doc pages. Then I was like, Boom:

TextInsideCircleButton.Builder builder = new TextInsideCircleButton.Builder();
builder.typeface(ResourcesCompat.getFont(this, R.font.my_custom_font));
builder.normalTextColor(R.color.colorAccent);

Thank you, Nightonke!

Comment

Problems with the new GPS Automatic License Notice Generator

Following up on my previous post, here’s a screenshot of the OSS license item for the popular Glide library as generated by version 11.2.2 of the new GPS OSS tools. There are two distinct OSS licenses for the Glide library and the GPS OSS tools finds both of them. But it concatenates the two URLs without a space or line break in between. They’re just stuck together:

To fix that, I added a gradle hack which runs after the app’s preBuild gradle task. The code block, placed at the bottom of build.gradle, carries out a specific edit within third_party_licenses (a text file generated by the OSS gradle plugin):

preBuild.doLast({
    String thirdPartyLicenseFilePath = 'app/src/main/res/raw/third_party_licenses'
    File thirdPartyLicenses = new File(thirdPartyLicenseFilePath)
    if (thirdPartyLicenses.exists()) {
        String contents = thirdPartyLicenses.getText('UTF-8')
        contents = contents.replace("licensehttp://", "license http://")
        thirdPartyLicenses.setText(contents, 'UTF-8')
    } else {
        println "cannot find " + thirdPartyLicenseFilePath
    }
})

Sure enough, the hack adds a space between the two urls:

But there’s a new problem: the ‘t’ at the very end of the second url is no longer present. (Look closely. The url points to a ‘.tx’ file instead of a ‘.txt’ file).

On one of my android devices, it appears that there’s a 92 character length limit on that string. Or something. I have yet to discover where that limit is set.

Comment

GPS Library’s New Automatic OSS License Notice

This will save developers work and eliminate errors in the process.

Google Play Services now offers an automatic way to list the open source software an app uses. The app developer no longer has to maintain a separate list of libraries in a dialog.

Instead, the new GPS Open Source Software gradle plugin will gather info from each library for you. If you add a new OSS library, this plugin will automatically add it to the notice. It’s one less task to remember.

The actual UI displays each library’s name as an item in a ListView. This is what it looks like (as of version 11.2.0):

(Note that I set that activity’s title to a custom string.)

When the user clicks an item, it displays some detailed info for that library. In this version, the info appears to be just an http URL to the license’s main online text:

Questions are handled at StackOverflow.

Comment

Android Percentage Based Layouts

It looks like Android is now offering percentage based spacing in a new layout object.

I believe Cascading Style Sheets had specified that feature by 1998.

Comment

TextView Plus SeekBar

One way to couple a dynamically updating TextView with a SeekBar is to use a TextSeekBar.

Comment

Android Library for Reading Bluetooth Data from a Contec Pulse Oximeter

I’ve released an open source library for reading the real-time Bluetooth data stream from a Contec Medical Systems Pulse Oximeter (model CMS50FW).

The test and demo app can be compiled from the Github source or or downloaded from the Google Play Store.

View 4 Comments

CMS50FWLib Test App Privacy Policy

This privacy policy governs your use of the software application CMS50FWLib Test App (“Application”) for mobile devices that was created by Albert Braun. The Application is designed to test the CMS50FWLib open source library.

User Provided Information

The Application obtains the information you provide when you download and install the Application.

Automatically Collected Information

The Application collects certain information about the way you use the Application. But, it does not persist heart rate, oxygen level or other data generated by the CMS50FW pulse oximeter.

Does the Application collect precise real time location information of the device?

This Application does not collect precise information about the location of your mobile device.

Do third parties see and/or have access to information obtained by the Application?

No.

What are my opt-out rights?

You can stop all collection of information by the Application easily by uninstalling the Application. You may use the standard uninstall processes as may be available as part of your mobile device or via the mobile application marketplace or network.

Data Retention Policy, Managing Your Information

The Application itself may retain User Provided data for as long as you use the Application and for a reasonable time thereafter. Please note that some or all of the User Provided Data may be required in order for the Application to function properly.

Children

We do not use the Application to knowingly solicit data from or market to children under the age of 13 or anyone else.

Security

We are concerned about safeguarding the confidentiality of your information. We provide physical, electronic, and procedural safeguards to protect information we process and maintain. For example, we limit access to this information to authorized employees and contractors who need to know that information in order to operate, develop or improve our Application. Please be aware that, although we endeavor to provide reasonable security for information we process and maintain, no security system can prevent all potential security breaches.

Changes

This Privacy Policy may be updated from time to time for any reason. We will notify you of any changes to our Privacy Policy by posting the new Privacy Policy at http://http://www.albertcbraun.com/cms50fwlib-test-app-privacy-policy/.

Your Consent

By using the Application, you are consenting to our processing of your information as set forth in this Privacy Policy now and as amended by us. “Processing” means using cookies on a computer/hand held device or using or touching information in any way, including, but not limited to, collecting, storing, deleting, using, combining and disclosing information, all of which activities will take place in the United States. If you reside outside the United States your information will be transferred, processed and stored there under United States privacy standards.

Contact us

If you have any questions regarding privacy while using the Application, or have questions about our practices, please contact us via email at me@albertcbraun.com

Comment

WifiDLite

WifiDLite is my experimental, alpha-version, open-source Android library which tries to make it easier to do basic WiFi Direct tasks.

The idea is to encapsulate away some of the nuts and bolts of programming Wifi Direct on Android and offer a simpler API for Wifi Direct tasks.

For example, WifiDLite spares you the work of getting an instance of WifiP2pManager, initializing it to get a Channel object, and implementing a specialized BroadcastListener.

Instead you simply get and initialize the WifiDLite singleton in your app’s onCreate, and then dispose of it in onDestroy.

The most experimental part of the library is the worker thread which periodically “rediscovers” peers on the WiFi Direct network. The default interval (set in the DefaultConfiguration object) is 10 seconds. The idea is to discover repeatedly so that, as other Android devices become available to the WiFi P2P network, your client code becomes aware of them shortly afterwards.

Of course, in theory, this is totally unnecessary because the Android platform automatically updates the internal BroadcastReceiver implementation with a WIFI_P2P_PEERS_CHANGED_ACTION when these event occurs. But … I thought I’d try explicitly forcing discovery to see what happens. (This feature may be removed in the future.) Aside from this experimental background thread, everything, including the client programmer’s calls to WifiDLite methods, should happen on the UI thread.

The source is offered as an Android Studio project on GitHub, which includes both the WifiDLite library (aar) project, and source code for the demo app. The demo app is also available on Google Play.

The pre-built Android Archive (aar) file is now available on jCenter (thanks to Blundell), which makes it easy to use the library in Android Studio. For example, add this line to the dependencies block in your app’s build.gradle to download and include version 0.1.1 of the library in your Android Studio project:

compile(group: 'com.albertcbraun.wifidlite', name: 'wifidlite-lib', version: '0.1.1', ext: 'aar')

More code samples are found in the demo app and in the ReadMe on GitHub.