Android TimePicker methods being stubs - android

(I am unsure if everyone else faces this problem, but I do)
I am accessing setHour(int) and getHour() (and the minute's getter and setter) of android.widget.TimePicker - IntelliJ doesn't complain of their inexistence, but when i run the program from my phone (or emulator) it crashes and i see an error log of java.lang.NoSuchMethodError android.widget.TimePicker.getHour. (Other minute/hour getter/setter include).
I tried accessing the definition for the TimePicker class (Ctrl+B) and I realised every method contained a line: throw RuntimeException("Stub");
So what's this; How can I move on?

IntelliJ doesn't complain of their inexistence
That is because you are compiling against API Level 23.
but when i run the program from my phone (or emulator) it crashes and i see an error log of java.lang.NoSuchMethodError android.widget.TimePicker.getHour
That is because getHour() was added in API Level 23, and your device or emulator is running Android 5.2 or below.
I don't use IntelliJ, but it should be complaining about your build. In Eclipse and Android Studio, you would get an error from Lint indicating that you are calling a method (getHour()) that exists in your compileSdkVersion (23) but does not exist in your minSdkVersion (whatever you have that set to, as the oldest API level that you are willing to support).
I tried accessing the definition for the TimePicker class (Ctrl+B) and I realised every method contained a line: throw RuntimeException("Stub")
That is because it is decompiling the android.jar that is in your compile-time classpath, which consists purely of stub implementations to satisfy the javac compiler. At runtime, your process' VM will have a version of that JAR that has actual implementations.
How can I move on?
Probably stop calling getHour(), unless you can get away with doing so only on Android 6.0+ devices.

Related

Android Studio minSdkVersion check for Java 1.8 (API level 24) specific features

My project uses Array#sort that requires API level 24 (Android 7.0)
_tmp.sort((left, right) -> { ... };
But I have also minSdkVersion 21 (Android 5.0)
When I run that code on Android 6.0 Emulator, the following exception is thrown:
... Caused by: java.lang.NoSuchMethodError: No interface method sort(Ljava/util/Comparator;)V in class Ljava/util/List; or its super classes (declaration of 'java.util.List' appears in /system/framework/core-libart.jar)
I have found that other users asked about this exception: java.lang.NoSuchMethodError: No interface method sort(Ljava/util/Comparator;) exception in sorting arraylist android
Any good way to Android Studio warns that .sort is not workable on OSes earlier than Android 7.0? like APIs having #RequiresApi?
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { ... }
Android studios on my computers warns my about this out of the box, not to sure why yours doesn't. Maybe you made changes to your lint warning configuration? If not, you should still be able to enable that there.
Sort method is annotated as #since 1.8
You can change Android Studio errors and warnings levels in Settings->Editor->Inspections
Try change Java->Java language level migration aids->usages of API which isn't available at her configure (description of it: "This inspection finds all usages of methods that have #since tag in their documentation.")

ServiceLoader.load is not finding the META-INF/services

So I want to build an extensible android application where developers can add 'CustomDevice' classes and the main program will run them automatically without editing existing code.
I've read about Service Provider interface and thought that would be a nice way to go about it.
So I tested it and created an interface called 'ICustomDevice' which custom device classes are expected to implement.
I've created a class called 'DummyDevice' that implements ICustomDevice.
Both DummyDevice and ICustomDevice are in the same package "CustomDevicePackage".
So in my main program I run the following.
ServiceLoader<ICustomDevice> loader = ServiceLoader.load(ICustomDevice.class);
Iterator<ICustomDevice> devices = loader.iterator();
System.out.println("Does it have devices? " + devices.hasNext());
It always returns false, which means it's not finding the 'DummyDevice'
In my eclipse project I created a folder at 'src' called META-INF and under it, a subfolder called 'services'.
'Services' has a file named 'CustomDevicePackage.ICustomDevice' with a line of content 'CustomDevicePackage.DummyDevice'.
Am I doing it right? Every example I see about SPI is about loading JARS.
I'm not loading a JAR, I'm trying to run a class in the same Project. Does this method only works for loading JARs? I want my program to support loading local subclasses and external JARs alike.
I am adding this as an answer but leaving the prior "answer" to provide extended code detail for this workaround. I am working on reporting the prior answer results as a bug to Google.
Because the Android implementation of java.util.ServiceLoader is broken (always populating internal java.security.AccessControlContext field with AccessController.getContext() even if System.getSecurityManager() == null), the workaround is to create your own ServiceLoader class by copying the code found at OpenJDK for Java 8 into your class, add specific imports required from java.util without using import java.util.*;, and call that ServiceLoader in your code (you will have to fully reference the ServiceLoader you created to over ambiguity).
This isn't elegant but it is a functional workaround that works! Also, you will need to use a ClassLoader in your ServiceLoader.load() call. That ClassLoader will either have to be YourClass.class.getClassLoader() or a child ClassLoader of the class' ClassLoader.
Though it's an old post, This may be still be of some help to others:
When I was running or debugging a project that contained a ServiceLoader Class, I had to put the META-INF/services folder into the src/ folder in Eclipse.
If I tried to export the project as Runnable jar and tried to use the class with the service loader, it never worked.
When I checked the jar, unzipping it, I found the folder under src/META-INF/services though.
Only when I also added the META-INF folder directly in the root directory of the jar, it started to work.
I haven't found a fix though inside Eclipse, that makes sure it gets exported right...maybe an ANT script can solve this issue, but so far no attempts made...
This is an answer:
At some point, Android removed the AccessControlContext field in ServiceLoader and ServiceLoader now works. As my comments indicate, this was reproduceable using the "out-of-the-box" OREO (API 26) Intel Atom x86 emulator with Android Studio (also fresh download). 24 hours later, ServiceLoader no longer contained the acc field (as shown in the Android Studio debugger with the same emulator). The Android SDKs dating back to API 24 do not show the acc field.
Per the Android developer currently maintaining the ServiceLoader code:
He is not aware of ServiceLoader ever having the acc field in Android (it did as we were able to reproduce) and thought the debugger/emulator might have been using JDK code (but I showed the OpenJDK code works correctly). Somewhere along the way, the errant code was updated and I am no longer able to reproduce.
Be sure your OS is up-to-date and you should no longer see this phenomena.

Android Lint limitations?

I recently discovered a fatal error in my android app running on Android version 10 from this line:
((Button)alert.findViewById(android.R.id.button1)).setAllCaps(true);
I have set android:minSdkVersion="9" in AndroidManifest.xml.
The root cause was android.widget.Button inherits from android.widget.TextView and the setAllCaps method was implemented in API level 14.
Reference: https://developer.android.com/reference/android/widget/TextView.html#setAllCaps(boolean)
So my question is why can't I get lint to discover this class of error?
I would presume that lint --check NewApi . would find this kind of issue.
Is it because the dialog which has this button is dynamically created just before this code?
Is there anything I can do to help lint prevent this class of error? In a perfect world I would like warnings to be thrown for any methods called from SDK versions higher than minSdk.

what is the use of #SuppressLint("InlinedApi")

I encountered #SuppressLint("InlinedApi") in some code i was going through and could not find out any description of it online. I understand #SuppressLint("NewApi") is used to hide warnings when we write code that is higher than the minsdk mentioned in the manifest. But i am not able to figure out when "InlinedApi" should be used. Any ideas?
By executing lint --list (the lint tool is located in your sdk/tools directory) you can see a list of the valid issue id's. You can find the explanation of InlinedApi there :
"InlinedApi": Finds inlined fields that may or may not work on older
platforms
Here's an example from a Google codelab:
#SuppressLint("InlinedApi")
private void hideSystemUi() {
mPlayerView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
If you comment out the #SuppressLint("InlinedApi"), you get this lint warning:
Field requires API level 19 (current min is 16): android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY
So you're accessing a field that may not exist in the API of some of the devices that you've said you want to be able to run the device on. In that case, why is it just a lint warning instead of a fatal compile error?
The fuller description for the warning is nice and informative. You can see it in Android Studio if you press the "More" key combo (e.g. Cmd+F1) when the lint message popup is open. You can also get it via lint on the command line, similar to what #stan0 said but in more detail:
lint --show InlinedApi
Here's the detailed explanation:
InlinedApi
----------
Summary: Using inlined constants on older versions
Priority: 6 / 10
Severity: Warning
Category: Correctness
This check scans through all the Android API field references in the
application and flags certain constants, such as static final integers
and Strings, which were introduced in later versions. These will
actually be copied into the class files rather than being referenced,
which means that the value is available even when running on older
devices. In some cases that's fine, and in other cases it can result
in a runtime crash or incorrect behavior. It depends on the context,
so consider the code carefully and decide whether it's safe and can be
suppressed or whether the code needs to be guarded. [emphasis added]
If you really want to use this API and don't need to support older
devices just set the minSdkVersion in your build.gradle or
AndroidManifest.xml files. If your code is deliberately accessing
newer APIs, and you have ensured (e.g. with conditional execution)
that this code will only ever be called on a supported platform, then
you can annotate your class or method with the #TargetApi annotation
specifying the local minimum SDK to apply, such as #TargetApi(11),
such that this check considers 11 rather than your manifest file's
minimum SDK as the required API level.
(source)
Hopefully with that explanation, it's clear why this is not a fatal error (because the value of the constant gets copied into the class file instead of a reference), why it's still potentially dangerous, and when to suppress the warning. In the codelab example above, the author apparently decided that adding a flag that wouldn't be recognized on older devices was safe. Maybe he had information that unrecognized flags would be silently ignored, though I don't see that in the documentation.
I found this..
#SuppressLint("InlinedApi")
Indicates that Lint should ignore the specified warnings for the annotated element.
Exp:
SuppressLint
implements from Annotation Class.
android.annotation.SuppressLint like this..
Built-In Annotations
Java defines a set of annotations that are built into the language
Annotations applied to java code:
#Override - Checks that the method is an override. Causes a compile error if the method is not found in one of the parent classes or implemented interfaces.
#Deprecated - Marks the method as obsolete. Causes a compile warning if the method is used.
#SuppressWarnings - Instructs the compiler to suppress the compile time warnings specified in the annotation parameters
http://developer.android.com/reference/java/lang/annotation/Annotation.html
http://developer.android.com/reference/android/annotation/SuppressLint.html

Problems with build.xml when using the Android ADK to communicate with an Arduino Mega ADK

So a few days ago I got my hands on an Arduino Mega ADK board, and the last couple of nights I have been setting up my development environment, getting to grips with the tools etc. The tools and libraries all work fine, for example I can get a program written in the Processing IDE to compile and run on an Asus Eee Pad Transformer TF101 running Android 4.03. But when I get it to try to compile and run one of the pre-written examples, it gives me a compiler error:
Android SDK Tools Revision 20
Installed at C:\NVPACK\android-sdk-windows
Project Type: Application
Project Target: Android 2.3.3
API level: 10
Library dependencies:
No Libraries
API<=15: Adding annotations.jar to the classpath.
Merging AndroidManifest files into one.
Manifest merger disabled. Using project manifest only.
No AIDL files to compile.
No RenderScript files to compile.
Generating resource IDs...
Generating BuildConfig class.
BUILD FAILED
C:\NVPACK\android-sdk-windows\tools\ant\build.xml:680: The following error occurred while executing this line:
C:\NVPACK\android-sdk-windows\tools\ant\build.xml:693: Compile failed; see the compiler error output for details.
Total time: 7 seconds
And that's all the console seems to output as well, which is rather frustrating! As far as I'm aware all of my SDK versions, tools and plugins are all up to date. I've tried this using a Linux partition I have on my hard drive and it produces the same error message, although it mentions a problem with the package com.Android.future.UsbAccessory. Given what I've seen, it seems that the problem is with the tools, either my directory structure doesn't match up to what the correct setup is, or something else is wrong :S. If anyone has had similar problems, some help would be smashing! (For the record, my setup was done using the instructions on the Arduino website, although I already had the Android SDK tools installed).
Will Scott-Jackson
It sounds like your haven't added in the support library to your project and/or you haven't downloaded it into your Android SDK.
The ADK1 demokit app targets API Level 10 (Android 2.3.3); That means you need to use the support libraries in your project and that's why the compiler is complaining about level 10 library dependencies not being available. The support libraries are a separate download in the SDK Manager, so you might not have them in your development environment.
In Android API Level 12 and higher, the USB Accessory protocol was added to the framework API, so there are two different ways to use the accessory protocol. So, you don't have to use the support libraries if you are targeting Honeycomb and higher versions, but you'll have to update the demokit app code to make this work.
Hope this helps.
So I've double checked my setup and started working on a project I had in mind, it seems to import the libraries appropriately. So far so good, but when I input:
ArduinoAdkUsb arduino;
void setup() {
arduino = new ArduinoAdkUsb(this);
//Other UI initialisation etc.
}
I get this error:
##name## ##version## by ##author##
FATAL EXCEPTION: Animation Thread
java.lang.NoClassDefFoundError: com.android.future.usb.UsbManager
at cc.arduino.ADKCommunication.<init>(Unknown Source)
at cc.arduino.ArduinoAdkUsb.<init>(Unknown Source)
at
processing.android.test.sketch_120730a.
sketch_120730a.setup(sketch_120730a.java:48)
at processing.core.PApplet.handleDraw(Unknown Source)
at processing.core.PGraphicsAndroid2D.requestDraw(Unknown Source)
at processing.core.PApplet.run(Unknown Source)
at java.lang.Thread.run(Thread.java:856)
After the app has been built and installed onto the Android tablet I am using. Any thoughts how I can over come this? From what I can tell, this has no problem finding com.android.future.usb.manager to compile and install the program, but once it tries to run it can find it.
Based on this tutorial from http://stream.tellart.com/controlling-arduino-with-android/
In the examples RGB_Arduino the name, version and author variables are set at the top of the sketch.
Try adding in this section of code at the top of your arduino sketch just underneath the library imports
// accessory descriptor. It's how Arduino identifies itself to Android
char applicationName[] = "Mega_ADK"; // the app on your phone
char accessoryName[] = "Mega_ADK"; // your Arduino board
char companyName[] = "Freeware";
// make up anything you want for these
char versionNumber[] = "1.0";
char serialNumber[] = "1";
char url[] = "http://labs.arduino.cc/adk/"; // the URL of your app online
//initialize the accessory:
AndroidAccessory usb(companyName, applicationName,
accessoryName,versionNumber,url,serialNumber);

Categories

Resources