// INSPECTION_CLASS: com.android.tools.idea.lint.AndroidLintNewApiInspection
// INSPECTION_CLASS2: com.android.tools.idea.lint.AndroidLintInlinedApiInspection
// INSPECTION_CLASS3: com.android.tools.idea.lint.AndroidLintOverrideInspection
import android.animation.RectEvaluator
import android.annotation.SuppressLint
import android.annotation.TargetApi
import org.w3c.dom.DOMError
import org.w3c.dom.DOMErrorHandler
import org.w3c.dom.DOMLocator
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams
import android.app.Activity
import android.app.ApplicationErrorReport
import android.graphics.drawable.VectorDrawable
import android.graphics.Path
import android.graphics.PorterDuff
import android.graphics.Rect
import android.os.Build
import android.widget.*
import dalvik.bytecode.OpcodeInfo
import android.os.Build.VERSION
import android.os.Build.VERSION.SDK_INT
import android.os.Build.VERSION_CODES
import android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH
import android.os.Build.VERSION_CODES.JELLY_BEAN
import android.os.Bundle
import android.os.Parcelable
import android.system.ErrnoException
import android.widget.TextView
@Suppress("SENSELESS_COMPARISON", "UNUSED_EXPRESSION", "UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION", "USELESS_CAST")
class ApiCallTest: Activity() {
fun method(chronometer: Chronometer, locator: DOMLocator) {
chronometer.setBackground(null)
// Ok
Bundle().getInt("")
View.SYSTEM_UI_FLAG_FULLSCREEN
// Virtual call
getActionBar() // API 11
actionBar // API 11
// Class references (no call or field access)
val error: DOMError? = null // API 8
val clz = DOMErrorHandler::class // API 8
// Method call
chronometer.onChronometerTickListener // API 3
// Inherited method call (from TextView
chronometer.setTextIsSelectable(true) // API 11
GridLayout::class
// Field access
val field = OpcodeInfo.MAXIMUM_VALUE // API 11
val fillParent = LayoutParams.FILL_PARENT // API 1
// This is a final int, which means it gets inlined
val matchParent = LayoutParams.MATCH_PARENT // API 8
// Field access: non final
val batteryInfo = report!!.batteryInfo
// Enum access
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
val mode = PorterDuff.Mode.OVERLAY // API 11
}
}
fun test(rect: Rect) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
RectEvaluator(rect); // OK
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (rect != null) {
RectEvaluator(rect); // OK
}
}
}
fun test2(rect: Rect) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
RectEvaluator(rect); // OK
}
}
fun test3(rect: Rect) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
RectEvaluator(); // ERROR
}
}
fun test4(rect: Rect) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
System.out.println("Something");
RectEvaluator(rect); // OK
} else {
RectEvaluator(rect); // ERROR
}
}
fun test5(rect: Rect) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) {
RectEvaluator(rect); // ERROR
} else {
RectEvaluator(rect); // ERROR
}
}
fun test(priority: Boolean, layout: ViewGroup) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Not flagged
} else {
GridLayout(null).getOrientation(); // Flagged
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Not flagged
} else {
GridLayout(null).getOrientation(); // Flagged
}
if (SDK_INT >= ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Not flagged
} else {
GridLayout(null).getOrientation(); // Flagged
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Not flagged
} else {
GridLayout(null).getOrientation(); // Flagged
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Flagged
} else {
GridLayout(null).getOrientation(); // Not flagged
}
if (Build.VERSION.SDK_INT >= 14) {
GridLayout(null).getOrientation(); // Not flagged
} else {
GridLayout(null).getOrientation(); // Flagged
}
if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Not flagged
} else {
GridLayout(null).getOrientation(); // Flagged
}
// Nested conditionals
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (priority) {
GridLayout(null).getOrientation(); // Flagged
} else {
GridLayout(null).getOrientation(); // Flagged
}
} else {
GridLayout(null).getOrientation(); // Flagged
}
// Nested conditionals 2
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (priority) {
GridLayout(null).getOrientation(); // Not flagged
} else {
GridLayout(null).getOrientation(); // Not flagged
}
} else {
GridLayout(null); // Flagged
}
}
fun test2(priority: Boolean) {
if (android.os.Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
GridLayout(null).getOrientation(); // Not flagged
} else {
GridLayout(null); // Flagged
}
if (android.os.Build.VERSION.SDK_INT >= 16) {
GridLayout(null).getOrientation(); // Not flagged
} else {
GridLayout(null); // Flagged
}
if (android.os.Build.VERSION.SDK_INT >= 13) {
GridLayout(null).getOrientation(); // Flagged
} else {
GridLayout(null); // Flagged
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
GridLayout(null).getOrientation(); // Not flagged
} else {
GridLayout(null); // Flagged
}
if (SDK_INT >= JELLY_BEAN) {
GridLayout(null).getOrientation(); // Not flagged
} else {
GridLayout(null); // Flagged
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
GridLayout(null).getOrientation(); // Not flagged
} else {
GridLayout(null); // Flagged
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
GridLayout(null); // Flagged
} else {
GridLayout(null).getOrientation(); // Not flagged
}
if (Build.VERSION.SDK_INT >= 16) {
GridLayout(null).getOrientation(); // Not flagged
} else {
GridLayout(null); // Flagged
}
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
GridLayout(null).getOrientation(); // Not flagged
} else {
GridLayout(null); // Flagged
}
}
fun test(textView: TextView) {
if (textView.isSuggestionsEnabled()) {
//ERROR
}
if (textView.isSuggestionsEnabled) {
//ERROR
}
if (SDK_INT >= JELLY_BEAN && textView.isSuggestionsEnabled()) {
//NO ERROR
}
if (SDK_INT >= JELLY_BEAN && textView.isSuggestionsEnabled) {
//NO ERROR
}
if (SDK_INT >= JELLY_BEAN && (textView.text != "" || textView.isSuggestionsEnabled)) {
//NO ERROR
}
if (SDK_INT < JELLY_BEAN && (textView.text != "" || textView.isSuggestionsEnabled)) {
//ERROR
}
if (SDK_INT < JELLY_BEAN && textView.isSuggestionsEnabled()) {
//ERROR
}
if (SDK_INT < JELLY_BEAN && textView.isSuggestionsEnabled) {
//ERROR
}
if (SDK_INT < JELLY_BEAN || textView.isSuggestionsEnabled) {
//NO ERROR
}
if (SDK_INT > JELLY_BEAN || textView.isSuggestionsEnabled) {
//ERROR
}
// getActionBar() API 11
if (SDK_INT <= 10 || getActionBar() == null) {
//NO ERROR
}
if (SDK_INT < 10 || getActionBar() == null) {
//ERROR
}
if (SDK_INT < 11 || getActionBar() == null) {
//NO ERROR
}
if (SDK_INT != 11 || getActionBar() == null) {
//NO ERROR
}
if (SDK_INT != 12 || getActionBar() == null) {
//ERROR
}
if (SDK_INT <= 11 || getActionBar() == null) {
//NO ERROR
}
if (SDK_INT < 12 || getActionBar() == null) {
//NO ERROR
}
if (SDK_INT <= 12 || getActionBar() == null) {
//NO ERROR
}
if (SDK_INT < 9 || getActionBar() == null) {
//ERROR
}
if (SDK_INT <= 9 || getActionBar() == null) {
//ERROR
}
}
fun testReturn() {
if (SDK_INT < 11) {
return
}
// No Error
val actionBar = getActionBar()
}
fun testThrow() {
if (SDK_INT < 11) {
throw IllegalStateException()
}
// No Error
val actionBar = getActionBar()
}
fun testError() {
if (SDK_INT < 11) {
error("Api")
}
// No Error
val actionBar = getActionBar()
}
fun testWithoutAnnotation(textView: TextView) {
if (textView.isSuggestionsEnabled()) {
}
if (textView.isSuggestionsEnabled) {
}
}
@TargetApi(JELLY_BEAN)
fun testWithTargetApiAnnotation(textView: TextView) {
if (textView.isSuggestionsEnabled()) {
//NO ERROR, annotation
}
if (textView.isSuggestionsEnabled) {
//NO ERROR, annotation
}
}
@SuppressLint("NewApi")
fun testWithSuppressLintAnnotation(textView: TextView) {
if (textView.isSuggestionsEnabled()) {
//NO ERROR, annotation
}
if (textView.isSuggestionsEnabled) {
//NO ERROR, annotation
}
}
fun testCatch() {
try {
} catch (e: ErrnoException) {
}
}
fun testOverload() {
// this overloaded addOval available only on API Level 21
Path().addOval(0f, 0f, 0f, 0f, Path.Direction.CW)
}
// KT-14737 False error with short-circuit evaluation
fun testShortCircuitEvaluation() {
getDrawable(0) // error here as expected
if(Build.VERSION.SDK_INT >= 23
&& null == getDrawable(0)) // error here should not occur
{
getDrawable(0) // no error here as expected
}
}
// KT-1482 Kotlin Lint: "Calling new methods on older versions" does not report call on receiver in extension function
private fun Bundle.caseE1a() { getBinder("") }
private fun Bundle.caseE1c() { this.getBinder("") }
private fun caseE1b(bundle: Bundle) { bundle.getBinder("") }
// KT-12023 Kotlin Lint: Cast doesn't trigger minSdk error
fun testCast(layout: ViewGroup) {
if (layout is LinearLayout) {} // OK API 1
layout as? LinearLayout // OK API 1
layout as LinearLayout // OK API 1
if (layout !is GridLayout) {}
layout as? GridLayout
layout as GridLayout
val grid = layout as? GridLayout
val linear = layout as LinearLayout // OK API 1
}
abstract class ErrorVectorDravable : VectorDrawable(), Parcelable
@TargetApi(21)
class MyVectorDravable : VectorDrawable()
fun testTypes() {
GridLayout(this)
val c = VectorDrawable::class.java
}
fun testCallWithApiAnnotation(textView: TextView) {
MyVectorDravable()
testWithTargetApiAnnotation(textView)
}
companion object : Activity() {
fun test() {
getDrawable(0)
}
}
// Return type
internal // API 14
val gridLayout: GridLayout?
get() = null
private val report: ApplicationErrorReport?
get() = null
}
object O: Activity() {
fun test() {
getDrawable(0)
}
}
fun testJava8() {
// Error, Api 24, Java8
mutableListOf(1, 2, 3).removeIf {
true
}
// Ok, Kotlin
mutableListOf(1, 2, 3).removeAll {
true
}
// Error, Api 24, Java8
mapOf(1 to 2).forEach { key, value -> key + value }
// Ok, Kotlin
mapOf(1 to 2).forEach { (key, value) -> key + value }
}
interface WithDefault {
// Should be ok
fun methodWithBody() {
return
}
}