Merge "Update linter formatting, add new tests" into tm-qpr-dev
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.systemui.lint
|
||||
|
||||
import com.android.SdkConstants.CLASS_CONTEXT
|
||||
import com.android.tools.lint.detector.api.Category
|
||||
import com.android.tools.lint.detector.api.Detector
|
||||
import com.android.tools.lint.detector.api.Implementation
|
||||
import com.android.tools.lint.detector.api.Issue
|
||||
import com.android.tools.lint.detector.api.JavaContext
|
||||
import com.android.tools.lint.detector.api.Scope
|
||||
import com.android.tools.lint.detector.api.Severity
|
||||
import com.android.tools.lint.detector.api.SourceCodeScanner
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.PsiModifierListOwner
|
||||
import org.jetbrains.uast.UCallExpression
|
||||
import org.jetbrains.uast.UClass
|
||||
import org.jetbrains.uast.UMethod
|
||||
import org.jetbrains.uast.getParentOfType
|
||||
|
||||
/**
|
||||
* Warns if {@code Context.bindService}, {@code Context.bindServiceAsUser}, or {@code
|
||||
* Context.unbindService} is not called on a {@code WorkerThread}
|
||||
*/
|
||||
@Suppress("UnstableApiUsage")
|
||||
class BindServiceOnMainThreadDetector : Detector(), SourceCodeScanner {
|
||||
|
||||
override fun getApplicableMethodNames(): List<String> {
|
||||
return listOf("bindService", "bindServiceAsUser", "unbindService")
|
||||
}
|
||||
|
||||
private fun hasWorkerThreadAnnotation(
|
||||
context: JavaContext,
|
||||
annotated: PsiModifierListOwner?
|
||||
): Boolean {
|
||||
return context.evaluator.getAnnotations(annotated, inHierarchy = true).any { uAnnotation ->
|
||||
uAnnotation.qualifiedName == "androidx.annotation.WorkerThread"
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
|
||||
if (context.evaluator.isMemberInSubClassOf(method, CLASS_CONTEXT)) {
|
||||
if (
|
||||
!hasWorkerThreadAnnotation(context, node.getParentOfType(UMethod::class.java)) &&
|
||||
!hasWorkerThreadAnnotation(context, node.getParentOfType(UClass::class.java))
|
||||
) {
|
||||
context.report(
|
||||
ISSUE,
|
||||
method,
|
||||
context.getLocation(node),
|
||||
"This method should be annotated with `@WorkerThread` because " +
|
||||
"it calls ${method.name}",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val ISSUE: Issue =
|
||||
Issue.create(
|
||||
id = "BindServiceOnMainThread",
|
||||
briefDescription = "Service bound or unbound on main thread",
|
||||
explanation =
|
||||
"""
|
||||
Binding and unbinding services are synchronous calls to `ActivityManager`. \
|
||||
They usually take multiple milliseconds to complete. If called on the main \
|
||||
thread, it will likely cause missed frames. To fix it, use a `@Background \
|
||||
Executor` and annotate the calling method with `@WorkerThread`.
|
||||
""",
|
||||
category = Category.PERFORMANCE,
|
||||
priority = 8,
|
||||
severity = Severity.WARNING,
|
||||
implementation =
|
||||
Implementation(
|
||||
BindServiceOnMainThreadDetector::class.java,
|
||||
Scope.JAVA_FILE_SCOPE
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.internal.systemui.lint
|
||||
|
||||
import com.android.SdkConstants.CLASS_CONTEXT
|
||||
import com.android.tools.lint.detector.api.Category
|
||||
import com.android.tools.lint.detector.api.Detector
|
||||
import com.android.tools.lint.detector.api.Implementation
|
||||
@@ -48,14 +49,14 @@ class BroadcastSentViaContextDetector : Detector(), SourceCodeScanner {
|
||||
return
|
||||
}
|
||||
|
||||
val evaulator = context.evaluator
|
||||
if (evaulator.isMemberInSubClassOf(method, "android.content.Context")) {
|
||||
val evaluator = context.evaluator
|
||||
if (evaluator.isMemberInSubClassOf(method, CLASS_CONTEXT)) {
|
||||
context.report(
|
||||
ISSUE,
|
||||
method,
|
||||
context.getNameLocation(node),
|
||||
"Please don't call sendBroadcast/sendBroadcastAsUser directly on " +
|
||||
"Context, use com.android.systemui.broadcast.BroadcastSender instead."
|
||||
"`Context.${method.name}()` should be replaced with " +
|
||||
"`BroadcastSender.${method.name}()`"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -65,14 +66,14 @@ class BroadcastSentViaContextDetector : Detector(), SourceCodeScanner {
|
||||
val ISSUE: Issue =
|
||||
Issue.create(
|
||||
id = "BroadcastSentViaContext",
|
||||
briefDescription = "Broadcast sent via Context instead of BroadcastSender.",
|
||||
explanation =
|
||||
"Broadcast was sent via " +
|
||||
"Context.sendBroadcast/Context.sendBroadcastAsUser. Please use " +
|
||||
"BroadcastSender.sendBroadcast/BroadcastSender.sendBroadcastAsUser " +
|
||||
"which will schedule dispatch of broadcasts on background thread. " +
|
||||
"Sending broadcasts on main thread causes jank due to synchronous " +
|
||||
"Binder calls.",
|
||||
briefDescription = "Broadcast sent via `Context` instead of `BroadcastSender`",
|
||||
// lint trims indents and converts \ to line continuations
|
||||
explanation = """
|
||||
Broadcasts sent via `Context.sendBroadcast()` or \
|
||||
`Context.sendBroadcastAsUser()` will block the main thread and may cause \
|
||||
missed frames. Instead, use `BroadcastSender.sendBroadcast()` or \
|
||||
`BroadcastSender.sendBroadcastAsUser()` which will schedule and dispatch \
|
||||
broadcasts on a background worker thread.""",
|
||||
category = Category.PERFORMANCE,
|
||||
priority = 8,
|
||||
severity = Severity.WARNING,
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.systemui.lint
|
||||
|
||||
import com.android.tools.lint.detector.api.Category
|
||||
import com.android.tools.lint.detector.api.Detector
|
||||
import com.android.tools.lint.detector.api.Implementation
|
||||
import com.android.tools.lint.detector.api.Issue
|
||||
import com.android.tools.lint.detector.api.JavaContext
|
||||
import com.android.tools.lint.detector.api.Scope
|
||||
import com.android.tools.lint.detector.api.Severity
|
||||
import com.android.tools.lint.detector.api.SourceCodeScanner
|
||||
import com.intellij.psi.PsiMethod
|
||||
import org.jetbrains.uast.UCallExpression
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
class GetMainLooperViaContextDetector : Detector(), SourceCodeScanner {
|
||||
|
||||
override fun getApplicableMethodNames(): List<String> {
|
||||
return listOf("getMainThreadHandler", "getMainLooper", "getMainExecutor")
|
||||
}
|
||||
|
||||
override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
|
||||
if (context.evaluator.isMemberInSubClassOf(method, "android.content.Context")) {
|
||||
context.report(
|
||||
ISSUE,
|
||||
method,
|
||||
context.getNameLocation(node),
|
||||
"Please inject a @Main Executor instead."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val ISSUE: Issue =
|
||||
Issue.create(
|
||||
id = "GetMainLooperViaContextDetector",
|
||||
briefDescription = "Please use idiomatic SystemUI executors, injecting " +
|
||||
"them via Dagger.",
|
||||
explanation = "Injecting the @Main Executor is preferred in order to make" +
|
||||
"dependencies explicit and increase testability. It's much " +
|
||||
"easier to pass a FakeExecutor on your test ctor than to " +
|
||||
"deal with loopers in unit tests.",
|
||||
category = Category.LINT,
|
||||
priority = 8,
|
||||
severity = Severity.WARNING,
|
||||
implementation = Implementation(GetMainLooperViaContextDetector::class.java,
|
||||
Scope.JAVA_FILE_SCOPE)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.internal.systemui.lint
|
||||
|
||||
import com.android.SdkConstants.CLASS_CONTEXT
|
||||
import com.android.tools.lint.detector.api.Category
|
||||
import com.android.tools.lint.detector.api.Detector
|
||||
import com.android.tools.lint.detector.api.Implementation
|
||||
@@ -28,20 +29,19 @@ import com.intellij.psi.PsiMethod
|
||||
import org.jetbrains.uast.UCallExpression
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
class BindServiceViaContextDetector : Detector(), SourceCodeScanner {
|
||||
class NonInjectedMainThreadDetector : Detector(), SourceCodeScanner {
|
||||
|
||||
override fun getApplicableMethodNames(): List<String> {
|
||||
return listOf("bindService", "bindServiceAsUser", "unbindService")
|
||||
return listOf("getMainThreadHandler", "getMainLooper", "getMainExecutor")
|
||||
}
|
||||
|
||||
override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
|
||||
if (context.evaluator.isMemberInSubClassOf(method, "android.content.Context")) {
|
||||
if (context.evaluator.isMemberInSubClassOf(method, CLASS_CONTEXT)) {
|
||||
context.report(
|
||||
ISSUE,
|
||||
method,
|
||||
context.getNameLocation(node),
|
||||
"Binding or unbinding services are synchronous calls, please make " +
|
||||
"sure you're on a @Background Executor."
|
||||
ISSUE,
|
||||
method,
|
||||
context.getNameLocation(node),
|
||||
"Replace with injected `@Main Executor`."
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -50,18 +50,20 @@ class BindServiceViaContextDetector : Detector(), SourceCodeScanner {
|
||||
@JvmField
|
||||
val ISSUE: Issue =
|
||||
Issue.create(
|
||||
id = "BindServiceViaContextDetector",
|
||||
briefDescription = "Service bound/unbound via Context, please make sure " +
|
||||
"you're on a background thread.",
|
||||
id = "NonInjectedMainThread",
|
||||
briefDescription = "Main thread usage without dependency injection",
|
||||
explanation =
|
||||
"Binding or unbinding services are synchronous calls to ActivityManager, " +
|
||||
"they usually take multiple milliseconds to complete and will make" +
|
||||
"the caller drop frames. Make sure you're on a @Background Executor.",
|
||||
category = Category.PERFORMANCE,
|
||||
"""
|
||||
Main thread should be injected using the `@Main Executor` instead \
|
||||
of using the accessors in `Context`. This is to make the \
|
||||
dependencies explicit and increase testability. It's much easier \
|
||||
to pass a `FakeExecutor` on test constructors than it is to deal \
|
||||
with loopers in unit tests.""",
|
||||
category = Category.LINT,
|
||||
priority = 8,
|
||||
severity = Severity.WARNING,
|
||||
implementation =
|
||||
Implementation(BindServiceViaContextDetector::class.java, Scope.JAVA_FILE_SCOPE)
|
||||
Implementation(NonInjectedMainThreadDetector::class.java, Scope.JAVA_FILE_SCOPE)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.internal.systemui.lint
|
||||
|
||||
import com.android.SdkConstants.CLASS_CONTEXT
|
||||
import com.android.tools.lint.detector.api.Category
|
||||
import com.android.tools.lint.detector.api.Detector
|
||||
import com.android.tools.lint.detector.api.Implementation
|
||||
@@ -32,7 +33,7 @@ import org.jetbrains.uast.UCallExpression
|
||||
class NonInjectedServiceDetector : Detector(), SourceCodeScanner {
|
||||
|
||||
override fun getApplicableMethodNames(): List<String> {
|
||||
return listOf("getSystemService")
|
||||
return listOf("getSystemService", "get")
|
||||
}
|
||||
|
||||
override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
|
||||
@@ -40,14 +41,25 @@ class NonInjectedServiceDetector : Detector(), SourceCodeScanner {
|
||||
if (
|
||||
!evaluator.isStatic(method) &&
|
||||
method.name == "getSystemService" &&
|
||||
method.containingClass?.qualifiedName == "android.content.Context"
|
||||
method.containingClass?.qualifiedName == CLASS_CONTEXT
|
||||
) {
|
||||
context.report(
|
||||
ISSUE,
|
||||
method,
|
||||
context.getNameLocation(node),
|
||||
"Use @Inject to get the handle to a system-level services instead of using " +
|
||||
"Context.getSystemService()"
|
||||
"Use `@Inject` to get system-level service handles instead of " +
|
||||
"`Context.getSystemService()`"
|
||||
)
|
||||
} else if (
|
||||
evaluator.isStatic(method) &&
|
||||
method.name == "get" &&
|
||||
method.containingClass?.qualifiedName == "android.accounts.AccountManager"
|
||||
) {
|
||||
context.report(
|
||||
ISSUE,
|
||||
method,
|
||||
context.getNameLocation(node),
|
||||
"Replace `AccountManager.get()` with an injected instance of `AccountManager`"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -57,14 +69,14 @@ class NonInjectedServiceDetector : Detector(), SourceCodeScanner {
|
||||
val ISSUE: Issue =
|
||||
Issue.create(
|
||||
id = "NonInjectedService",
|
||||
briefDescription =
|
||||
"System-level services should be retrieved using " +
|
||||
"@Inject instead of Context.getSystemService().",
|
||||
briefDescription = "System service not injected",
|
||||
explanation =
|
||||
"Context.getSystemService() should be avoided because it makes testing " +
|
||||
"difficult. Instead, use an injected service. For example, " +
|
||||
"instead of calling Context.getSystemService(UserManager.class), " +
|
||||
"use @Inject and add UserManager to the constructor",
|
||||
"""
|
||||
`Context.getSystemService()` should be avoided because it makes testing \
|
||||
difficult. Instead, use an injected service. For example, instead of calling \
|
||||
`Context.getSystemService(UserManager.class)` in a class, annotate the class' \
|
||||
constructor with `@Inject` and add `UserManager` to the parameters.
|
||||
""",
|
||||
category = Category.CORRECTNESS,
|
||||
priority = 8,
|
||||
severity = Severity.WARNING,
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.internal.systemui.lint
|
||||
|
||||
import com.android.SdkConstants.CLASS_CONTEXT
|
||||
import com.android.tools.lint.detector.api.Category
|
||||
import com.android.tools.lint.detector.api.Detector
|
||||
import com.android.tools.lint.detector.api.Implementation
|
||||
@@ -35,12 +36,12 @@ class RegisterReceiverViaContextDetector : Detector(), SourceCodeScanner {
|
||||
}
|
||||
|
||||
override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
|
||||
if (context.evaluator.isMemberInSubClassOf(method, "android.content.Context")) {
|
||||
if (context.evaluator.isMemberInSubClassOf(method, CLASS_CONTEXT)) {
|
||||
context.report(
|
||||
ISSUE,
|
||||
method,
|
||||
context.getNameLocation(node),
|
||||
"BroadcastReceivers should be registered via BroadcastDispatcher."
|
||||
"Register `BroadcastReceiver` using `BroadcastDispatcher` instead of `Context`"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -49,14 +50,16 @@ class RegisterReceiverViaContextDetector : Detector(), SourceCodeScanner {
|
||||
@JvmField
|
||||
val ISSUE: Issue =
|
||||
Issue.create(
|
||||
id = "RegisterReceiverViaContextDetector",
|
||||
briefDescription = "Broadcast registrations via Context are blocking " +
|
||||
"calls. Please use BroadcastDispatcher.",
|
||||
explanation =
|
||||
"Context#registerReceiver is a blocking call to the system server, " +
|
||||
"making it very likely that you'll drop a frame. Please use " +
|
||||
"BroadcastDispatcher instead (or move this call to a " +
|
||||
"@Background Executor.)",
|
||||
id = "RegisterReceiverViaContext",
|
||||
briefDescription = "Blocking broadcast registration",
|
||||
// lint trims indents and converts \ to line continuations
|
||||
explanation = """
|
||||
`Context.registerReceiver()` is a blocking call to the system server, \
|
||||
making it very likely that you'll drop a frame. Please use \
|
||||
`BroadcastDispatcher` instead, which registers the receiver on a \
|
||||
background thread. `BroadcastDispatcher` also improves our visibility \
|
||||
into ANRs.""",
|
||||
moreInfo = "go/identifying-broadcast-threads",
|
||||
category = Category.PERFORMANCE,
|
||||
priority = 8,
|
||||
severity = Severity.WARNING,
|
||||
|
||||
@@ -49,8 +49,7 @@ class SlowUserQueryDetector : Detector(), SourceCodeScanner {
|
||||
ISSUE_SLOW_USER_ID_QUERY,
|
||||
method,
|
||||
context.getNameLocation(node),
|
||||
"ActivityManager.getCurrentUser() is slow. " +
|
||||
"Use UserTracker.getUserId() instead."
|
||||
"Use `UserTracker.getUserId()` instead of `ActivityManager.getCurrentUser()`"
|
||||
)
|
||||
}
|
||||
if (
|
||||
@@ -62,7 +61,7 @@ class SlowUserQueryDetector : Detector(), SourceCodeScanner {
|
||||
ISSUE_SLOW_USER_INFO_QUERY,
|
||||
method,
|
||||
context.getNameLocation(node),
|
||||
"UserManager.getUserInfo() is slow. " + "Use UserTracker.getUserInfo() instead."
|
||||
"Use `UserTracker.getUserInfo()` instead of `UserManager.getUserInfo()`"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -72,11 +71,13 @@ class SlowUserQueryDetector : Detector(), SourceCodeScanner {
|
||||
val ISSUE_SLOW_USER_ID_QUERY: Issue =
|
||||
Issue.create(
|
||||
id = "SlowUserIdQuery",
|
||||
briefDescription = "User ID queried using ActivityManager instead of UserTracker.",
|
||||
briefDescription = "User ID queried using ActivityManager",
|
||||
explanation =
|
||||
"ActivityManager.getCurrentUser() makes a binder call and is slow. " +
|
||||
"Instead, inject a UserTracker and call UserTracker.getUserId(). For " +
|
||||
"more info, see: http://go/multi-user-in-systemui-slides",
|
||||
"""
|
||||
`ActivityManager.getCurrentUser()` uses a blocking binder call and is slow. \
|
||||
Instead, inject a `UserTracker` and call `UserTracker.getUserId()`.
|
||||
""",
|
||||
moreInfo = "http://go/multi-user-in-systemui-slides",
|
||||
category = Category.PERFORMANCE,
|
||||
priority = 8,
|
||||
severity = Severity.WARNING,
|
||||
@@ -88,11 +89,13 @@ class SlowUserQueryDetector : Detector(), SourceCodeScanner {
|
||||
val ISSUE_SLOW_USER_INFO_QUERY: Issue =
|
||||
Issue.create(
|
||||
id = "SlowUserInfoQuery",
|
||||
briefDescription = "User info queried using UserManager instead of UserTracker.",
|
||||
briefDescription = "User info queried using UserManager",
|
||||
explanation =
|
||||
"UserManager.getUserInfo() makes a binder call and is slow. " +
|
||||
"Instead, inject a UserTracker and call UserTracker.getUserInfo(). For " +
|
||||
"more info, see: http://go/multi-user-in-systemui-slides",
|
||||
"""
|
||||
`UserManager.getUserInfo()` uses a blocking binder call and is slow. \
|
||||
Instead, inject a `UserTracker` and call `UserTracker.getUserInfo()`.
|
||||
""",
|
||||
moreInfo = "http://go/multi-user-in-systemui-slides",
|
||||
category = Category.PERFORMANCE,
|
||||
priority = 8,
|
||||
severity = Severity.WARNING,
|
||||
|
||||
@@ -47,7 +47,7 @@ class SoftwareBitmapDetector : Detector(), SourceCodeScanner {
|
||||
ISSUE,
|
||||
referenced,
|
||||
context.getNameLocation(referenced),
|
||||
"Usage of Config.HARDWARE is highly encouraged."
|
||||
"Replace software bitmap with `Config.HARDWARE`"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -56,12 +56,12 @@ class SoftwareBitmapDetector : Detector(), SourceCodeScanner {
|
||||
@JvmField
|
||||
val ISSUE: Issue =
|
||||
Issue.create(
|
||||
id = "SoftwareBitmapDetector",
|
||||
briefDescription = "Software bitmap detected. Please use Config.HARDWARE instead.",
|
||||
explanation =
|
||||
"Software bitmaps occupy twice as much memory, when compared to Config.HARDWARE. " +
|
||||
"In case you need to manipulate the pixels, please consider to either use" +
|
||||
"a shader (encouraged), or a short lived software bitmap.",
|
||||
id = "SoftwareBitmap",
|
||||
briefDescription = "Software bitmap",
|
||||
explanation = """
|
||||
Software bitmaps occupy twice as much memory as `Config.HARDWARE` bitmaps \
|
||||
do. However, hardware bitmaps are read-only. If you need to manipulate the \
|
||||
pixels, use a shader (preferably) or a short lived software bitmap.""",
|
||||
category = Category.PERFORMANCE,
|
||||
priority = 8,
|
||||
severity = Severity.WARNING,
|
||||
|
||||
@@ -28,11 +28,11 @@ class SystemUIIssueRegistry : IssueRegistry() {
|
||||
|
||||
override val issues: List<Issue>
|
||||
get() = listOf(
|
||||
BindServiceViaContextDetector.ISSUE,
|
||||
BindServiceOnMainThreadDetector.ISSUE,
|
||||
BroadcastSentViaContextDetector.ISSUE,
|
||||
SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
|
||||
SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY,
|
||||
GetMainLooperViaContextDetector.ISSUE,
|
||||
NonInjectedMainThreadDetector.ISSUE,
|
||||
RegisterReceiverViaContextDetector.ISSUE,
|
||||
SoftwareBitmapDetector.ISSUE,
|
||||
NonInjectedServiceDetector.ISSUE,
|
||||
|
||||
@@ -16,16 +16,21 @@
|
||||
|
||||
package com.android.internal.systemui.lint
|
||||
|
||||
import com.android.annotations.NonNull
|
||||
import com.android.tools.lint.checks.infrastructure.LintDetectorTest.java
|
||||
import org.intellij.lang.annotations.Language
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
@NonNull
|
||||
private fun indentedJava(@NonNull @Language("JAVA") source: String) = java(source).indented()
|
||||
|
||||
/*
|
||||
* This file contains stubs of framework APIs and System UI classes for testing purposes only. The
|
||||
* stubs are not used in the lint detectors themselves.
|
||||
*/
|
||||
@Suppress("UnstableApiUsage")
|
||||
internal val androidStubs =
|
||||
arrayOf(
|
||||
java(
|
||||
indentedJava(
|
||||
"""
|
||||
package android.app;
|
||||
|
||||
@@ -34,7 +39,16 @@ public class ActivityManager {
|
||||
}
|
||||
"""
|
||||
),
|
||||
java(
|
||||
indentedJava(
|
||||
"""
|
||||
package android.accounts;
|
||||
|
||||
public class AccountManager {
|
||||
public static AccountManager get(Context context) { return null; }
|
||||
}
|
||||
"""
|
||||
),
|
||||
indentedJava(
|
||||
"""
|
||||
package android.os;
|
||||
import android.content.pm.UserInfo;
|
||||
@@ -45,39 +59,39 @@ public class UserManager {
|
||||
}
|
||||
"""
|
||||
),
|
||||
java("""
|
||||
indentedJava("""
|
||||
package android.annotation;
|
||||
|
||||
public @interface UserIdInt {}
|
||||
"""),
|
||||
java("""
|
||||
indentedJava("""
|
||||
package android.content.pm;
|
||||
|
||||
public class UserInfo {}
|
||||
"""),
|
||||
java("""
|
||||
indentedJava("""
|
||||
package android.os;
|
||||
|
||||
public class Looper {}
|
||||
"""),
|
||||
java("""
|
||||
indentedJava("""
|
||||
package android.os;
|
||||
|
||||
public class Handler {}
|
||||
"""),
|
||||
java("""
|
||||
indentedJava("""
|
||||
package android.content;
|
||||
|
||||
public class ServiceConnection {}
|
||||
"""),
|
||||
java("""
|
||||
indentedJava("""
|
||||
package android.os;
|
||||
|
||||
public enum UserHandle {
|
||||
ALL
|
||||
}
|
||||
"""),
|
||||
java(
|
||||
indentedJava(
|
||||
"""
|
||||
package android.content;
|
||||
import android.os.UserHandle;
|
||||
@@ -108,7 +122,7 @@ public class Context {
|
||||
}
|
||||
"""
|
||||
),
|
||||
java(
|
||||
indentedJava(
|
||||
"""
|
||||
package android.app;
|
||||
import android.content.Context;
|
||||
@@ -116,7 +130,7 @@ import android.content.Context;
|
||||
public class Activity extends Context {}
|
||||
"""
|
||||
),
|
||||
java(
|
||||
indentedJava(
|
||||
"""
|
||||
package android.graphics;
|
||||
|
||||
@@ -132,17 +146,17 @@ public class Bitmap {
|
||||
}
|
||||
"""
|
||||
),
|
||||
java("""
|
||||
indentedJava("""
|
||||
package android.content;
|
||||
|
||||
public class BroadcastReceiver {}
|
||||
"""),
|
||||
java("""
|
||||
indentedJava("""
|
||||
package android.content;
|
||||
|
||||
public class IntentFilter {}
|
||||
"""),
|
||||
java(
|
||||
indentedJava(
|
||||
"""
|
||||
package com.android.systemui.settings;
|
||||
import android.content.pm.UserInfo;
|
||||
@@ -151,6 +165,25 @@ public interface UserTracker {
|
||||
int getUserId();
|
||||
UserInfo getUserInfo();
|
||||
}
|
||||
"""
|
||||
),
|
||||
indentedJava(
|
||||
"""
|
||||
package androidx.annotation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.CONSTRUCTOR;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.PARAMETER;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
@Retention(SOURCE)
|
||||
@Target({METHOD,CONSTRUCTOR,TYPE,PARAMETER})
|
||||
public @interface WorkerThread {
|
||||
}
|
||||
"""
|
||||
),
|
||||
)
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.systemui.lint
|
||||
|
||||
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
|
||||
import com.android.tools.lint.checks.infrastructure.TestFiles
|
||||
import com.android.tools.lint.checks.infrastructure.TestLintTask
|
||||
import com.android.tools.lint.detector.api.Detector
|
||||
import com.android.tools.lint.detector.api.Issue
|
||||
import org.junit.Test
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
class BindServiceOnMainThreadDetectorTest : LintDetectorTest() {
|
||||
|
||||
override fun getDetector(): Detector = BindServiceOnMainThreadDetector()
|
||||
override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
|
||||
|
||||
override fun getIssues(): List<Issue> = listOf(BindServiceOnMainThreadDetector.ISSUE)
|
||||
|
||||
@Test
|
||||
fun testBindService() {
|
||||
lint()
|
||||
.files(
|
||||
TestFiles.java(
|
||||
"""
|
||||
package test.pkg;
|
||||
import android.content.Context;
|
||||
|
||||
public class TestClass {
|
||||
public void bind(Context context) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
context.bindService(intent, null, 0);
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
.indented(),
|
||||
*stubs
|
||||
)
|
||||
.issues(BindServiceOnMainThreadDetector.ISSUE)
|
||||
.run()
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:7: Warning: This method should be annotated with @WorkerThread because it calls bindService [BindServiceOnMainThread]
|
||||
context.bindService(intent, null, 0);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBindServiceAsUser() {
|
||||
lint()
|
||||
.files(
|
||||
TestFiles.java(
|
||||
"""
|
||||
package test.pkg;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
|
||||
public class TestClass {
|
||||
public void bind(Context context) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
context.bindServiceAsUser(intent, null, 0, UserHandle.ALL);
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
.indented(),
|
||||
*stubs
|
||||
)
|
||||
.issues(BindServiceOnMainThreadDetector.ISSUE)
|
||||
.run()
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:8: Warning: This method should be annotated with @WorkerThread because it calls bindServiceAsUser [BindServiceOnMainThread]
|
||||
context.bindServiceAsUser(intent, null, 0, UserHandle.ALL);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnbindService() {
|
||||
lint()
|
||||
.files(
|
||||
TestFiles.java(
|
||||
"""
|
||||
package test.pkg;
|
||||
import android.content.Context;
|
||||
import android.content.ServiceConnection;
|
||||
|
||||
public class TestClass {
|
||||
public void unbind(Context context, ServiceConnection connection) {
|
||||
context.unbindService(connection);
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
.indented(),
|
||||
*stubs
|
||||
)
|
||||
.issues(BindServiceOnMainThreadDetector.ISSUE)
|
||||
.run()
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:7: Warning: This method should be annotated with @WorkerThread because it calls unbindService [BindServiceOnMainThread]
|
||||
context.unbindService(connection);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testWorkerMethod() {
|
||||
lint()
|
||||
.files(
|
||||
TestFiles.java(
|
||||
"""
|
||||
package test.pkg;
|
||||
import android.content.Context;
|
||||
import android.content.ServiceConnection;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
public class TestClass {
|
||||
@WorkerThread
|
||||
public void unbind(Context context, ServiceConnection connection) {
|
||||
context.unbindService(connection);
|
||||
}
|
||||
}
|
||||
|
||||
public class ChildTestClass extends TestClass {
|
||||
@Override
|
||||
public void unbind(Context context, ServiceConnection connection) {
|
||||
context.unbindService(connection);
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
.indented(),
|
||||
*stubs
|
||||
)
|
||||
.issues(BindServiceOnMainThreadDetector.ISSUE)
|
||||
.run()
|
||||
.expectClean()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testWorkerClass() {
|
||||
lint()
|
||||
.files(
|
||||
TestFiles.java(
|
||||
"""
|
||||
package test.pkg;
|
||||
import android.content.Context;
|
||||
import android.content.ServiceConnection;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
@WorkerThread
|
||||
public class TestClass {
|
||||
public void unbind(Context context, ServiceConnection connection) {
|
||||
context.unbindService(connection);
|
||||
}
|
||||
}
|
||||
|
||||
public class ChildTestClass extends TestClass {
|
||||
@Override
|
||||
public void unbind(Context context, ServiceConnection connection) {
|
||||
context.unbindService(connection);
|
||||
}
|
||||
|
||||
public void bind(Context context, ServiceConnection connection) {
|
||||
context.bind(connection);
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
.indented(),
|
||||
*stubs
|
||||
)
|
||||
.issues(BindServiceOnMainThreadDetector.ISSUE)
|
||||
.run()
|
||||
.expectClean()
|
||||
}
|
||||
|
||||
private val stubs = androidStubs
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.systemui.lint
|
||||
|
||||
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
|
||||
import com.android.tools.lint.checks.infrastructure.TestFiles
|
||||
import com.android.tools.lint.checks.infrastructure.TestLintTask
|
||||
import com.android.tools.lint.detector.api.Detector
|
||||
import com.android.tools.lint.detector.api.Issue
|
||||
import org.junit.Test
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
class BindServiceViaContextDetectorTest : LintDetectorTest() {
|
||||
|
||||
override fun getDetector(): Detector = BindServiceViaContextDetector()
|
||||
override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
|
||||
|
||||
override fun getIssues(): List<Issue> = listOf(BindServiceViaContextDetector.ISSUE)
|
||||
|
||||
private val explanation = "Binding or unbinding services are synchronous calls"
|
||||
|
||||
@Test
|
||||
fun testBindService() {
|
||||
lint()
|
||||
.files(
|
||||
TestFiles.java(
|
||||
"""
|
||||
package test.pkg;
|
||||
import android.content.Context;
|
||||
|
||||
public class TestClass1 {
|
||||
public void bind(Context context) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
context.bindService(intent, null, 0);
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
.indented(),
|
||||
*stubs
|
||||
)
|
||||
.issues(BindServiceViaContextDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains(explanation)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBindServiceAsUser() {
|
||||
lint()
|
||||
.files(
|
||||
TestFiles.java(
|
||||
"""
|
||||
package test.pkg;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
|
||||
public class TestClass1 {
|
||||
public void bind(Context context) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
context.bindServiceAsUser(intent, null, 0, UserHandle.ALL);
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
.indented(),
|
||||
*stubs
|
||||
)
|
||||
.issues(BindServiceViaContextDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains(explanation)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnbindService() {
|
||||
lint()
|
||||
.files(
|
||||
TestFiles.java(
|
||||
"""
|
||||
package test.pkg;
|
||||
import android.content.Context;
|
||||
import android.content.ServiceConnection;
|
||||
|
||||
public class TestClass1 {
|
||||
public void unbind(Context context, ServiceConnection connection) {
|
||||
context.unbindService(connection);
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
.indented(),
|
||||
*stubs
|
||||
)
|
||||
.issues(BindServiceViaContextDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains(explanation)
|
||||
}
|
||||
|
||||
private val stubs = androidStubs
|
||||
}
|
||||
@@ -41,7 +41,7 @@ class BroadcastSentViaContextDetectorTest : LintDetectorTest() {
|
||||
package test.pkg;
|
||||
import android.content.Context;
|
||||
|
||||
public class TestClass1 {
|
||||
public class TestClass {
|
||||
public void send(Context context) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
context.sendBroadcast(intent);
|
||||
@@ -54,10 +54,13 @@ class BroadcastSentViaContextDetectorTest : LintDetectorTest() {
|
||||
)
|
||||
.issues(BroadcastSentViaContextDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains(
|
||||
"Please don't call sendBroadcast/sendBroadcastAsUser directly on " +
|
||||
"Context, use com.android.systemui.broadcast.BroadcastSender instead."
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:7: Warning: Context.sendBroadcast() should be replaced with BroadcastSender.sendBroadcast() [BroadcastSentViaContext]
|
||||
context.sendBroadcast(intent);
|
||||
~~~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@@ -71,7 +74,7 @@ class BroadcastSentViaContextDetectorTest : LintDetectorTest() {
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
|
||||
public class TestClass1 {
|
||||
public class TestClass {
|
||||
public void send(Context context) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
context.sendBroadcastAsUser(intent, UserHandle.ALL, "permission");
|
||||
@@ -84,10 +87,13 @@ class BroadcastSentViaContextDetectorTest : LintDetectorTest() {
|
||||
)
|
||||
.issues(BroadcastSentViaContextDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains(
|
||||
"Please don't call sendBroadcast/sendBroadcastAsUser directly on " +
|
||||
"Context, use com.android.systemui.broadcast.BroadcastSender instead."
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:8: Warning: Context.sendBroadcastAsUser() should be replaced with BroadcastSender.sendBroadcastAsUser() [BroadcastSentViaContext]
|
||||
context.sendBroadcastAsUser(intent, UserHandle.ALL, "permission");
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@@ -101,7 +107,7 @@ class BroadcastSentViaContextDetectorTest : LintDetectorTest() {
|
||||
import android.app.Activity;
|
||||
import android.os.UserHandle;
|
||||
|
||||
public class TestClass1 {
|
||||
public class TestClass {
|
||||
public void send(Activity activity) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
activity.sendBroadcastAsUser(intent, UserHandle.ALL, "permission");
|
||||
@@ -115,13 +121,43 @@ class BroadcastSentViaContextDetectorTest : LintDetectorTest() {
|
||||
)
|
||||
.issues(BroadcastSentViaContextDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains(
|
||||
"Please don't call sendBroadcast/sendBroadcastAsUser directly on " +
|
||||
"Context, use com.android.systemui.broadcast.BroadcastSender instead."
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:8: Warning: Context.sendBroadcastAsUser() should be replaced with BroadcastSender.sendBroadcastAsUser() [BroadcastSentViaContext]
|
||||
activity.sendBroadcastAsUser(intent, UserHandle.ALL, "permission");
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSendBroadcastInBroadcastSender() {
|
||||
lint()
|
||||
.files(
|
||||
TestFiles.java(
|
||||
"""
|
||||
package com.android.systemui.broadcast;
|
||||
import android.app.Activity;
|
||||
import android.os.UserHandle;
|
||||
|
||||
public class BroadcastSender {
|
||||
public void send(Activity activity) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
activity.sendBroadcastAsUser(intent, UserHandle.ALL, "permission");
|
||||
}
|
||||
|
||||
}
|
||||
"""
|
||||
)
|
||||
.indented(),
|
||||
*stubs
|
||||
)
|
||||
.issues(BroadcastSentViaContextDetector.ISSUE)
|
||||
.run()
|
||||
.expectClean()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNoopIfNoCall() {
|
||||
lint()
|
||||
@@ -131,7 +167,7 @@ class BroadcastSentViaContextDetectorTest : LintDetectorTest() {
|
||||
package test.pkg;
|
||||
import android.content.Context;
|
||||
|
||||
public class TestClass1 {
|
||||
public class TestClass {
|
||||
public void sendBroadcast() {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
context.startActivity(intent);
|
||||
|
||||
@@ -24,14 +24,12 @@ import com.android.tools.lint.detector.api.Issue
|
||||
import org.junit.Test
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
class GetMainLooperViaContextDetectorTest : LintDetectorTest() {
|
||||
class NonInjectedMainThreadDetectorTest : LintDetectorTest() {
|
||||
|
||||
override fun getDetector(): Detector = GetMainLooperViaContextDetector()
|
||||
override fun getDetector(): Detector = NonInjectedMainThreadDetector()
|
||||
override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
|
||||
|
||||
override fun getIssues(): List<Issue> = listOf(GetMainLooperViaContextDetector.ISSUE)
|
||||
|
||||
private val explanation = "Please inject a @Main Executor instead."
|
||||
override fun getIssues(): List<Issue> = listOf(NonInjectedMainThreadDetector.ISSUE)
|
||||
|
||||
@Test
|
||||
fun testGetMainThreadHandler() {
|
||||
@@ -43,7 +41,7 @@ class GetMainLooperViaContextDetectorTest : LintDetectorTest() {
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
|
||||
public class TestClass1 {
|
||||
public class TestClass {
|
||||
public void test(Context context) {
|
||||
Handler mainThreadHandler = context.getMainThreadHandler();
|
||||
}
|
||||
@@ -53,10 +51,16 @@ class GetMainLooperViaContextDetectorTest : LintDetectorTest() {
|
||||
.indented(),
|
||||
*stubs
|
||||
)
|
||||
.issues(GetMainLooperViaContextDetector.ISSUE)
|
||||
.issues(NonInjectedMainThreadDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains(explanation)
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:7: Warning: Replace with injected @Main Executor. [NonInjectedMainThread]
|
||||
Handler mainThreadHandler = context.getMainThreadHandler();
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -69,7 +73,7 @@ class GetMainLooperViaContextDetectorTest : LintDetectorTest() {
|
||||
import android.content.Context;
|
||||
import android.os.Looper;
|
||||
|
||||
public class TestClass1 {
|
||||
public class TestClass {
|
||||
public void test(Context context) {
|
||||
Looper mainLooper = context.getMainLooper();
|
||||
}
|
||||
@@ -79,10 +83,16 @@ class GetMainLooperViaContextDetectorTest : LintDetectorTest() {
|
||||
.indented(),
|
||||
*stubs
|
||||
)
|
||||
.issues(GetMainLooperViaContextDetector.ISSUE)
|
||||
.issues(NonInjectedMainThreadDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains(explanation)
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:7: Warning: Replace with injected @Main Executor. [NonInjectedMainThread]
|
||||
Looper mainLooper = context.getMainLooper();
|
||||
~~~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -95,7 +105,7 @@ class GetMainLooperViaContextDetectorTest : LintDetectorTest() {
|
||||
import android.content.Context;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class TestClass1 {
|
||||
public class TestClass {
|
||||
public void test(Context context) {
|
||||
Executor mainExecutor = context.getMainExecutor();
|
||||
}
|
||||
@@ -105,10 +115,16 @@ class GetMainLooperViaContextDetectorTest : LintDetectorTest() {
|
||||
.indented(),
|
||||
*stubs
|
||||
)
|
||||
.issues(GetMainLooperViaContextDetector.ISSUE)
|
||||
.issues(NonInjectedMainThreadDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains(explanation)
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:7: Warning: Replace with injected @Main Executor. [NonInjectedMainThread]
|
||||
Executor mainExecutor = context.getMainExecutor();
|
||||
~~~~~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
private val stubs = androidStubs
|
||||
@@ -39,7 +39,7 @@ class NonInjectedServiceDetectorTest : LintDetectorTest() {
|
||||
package test.pkg;
|
||||
import android.content.Context;
|
||||
|
||||
public class TestClass1 {
|
||||
public class TestClass {
|
||||
public void getSystemServiceWithoutDagger(Context context) {
|
||||
context.getSystemService("user");
|
||||
}
|
||||
@@ -51,8 +51,14 @@ class NonInjectedServiceDetectorTest : LintDetectorTest() {
|
||||
)
|
||||
.issues(NonInjectedServiceDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains("Use @Inject to get the handle")
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:6: Warning: Use @Inject to get system-level service handles instead of Context.getSystemService() [NonInjectedService]
|
||||
context.getSystemService("user");
|
||||
~~~~~~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -65,7 +71,7 @@ class NonInjectedServiceDetectorTest : LintDetectorTest() {
|
||||
import android.content.Context;
|
||||
import android.os.UserManager;
|
||||
|
||||
public class TestClass2 {
|
||||
public class TestClass {
|
||||
public void getSystemServiceWithoutDagger(Context context) {
|
||||
context.getSystemService(UserManager.class);
|
||||
}
|
||||
@@ -77,8 +83,46 @@ class NonInjectedServiceDetectorTest : LintDetectorTest() {
|
||||
)
|
||||
.issues(NonInjectedServiceDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains("Use @Inject to get the handle")
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:7: Warning: Use @Inject to get system-level service handles instead of Context.getSystemService() [NonInjectedService]
|
||||
context.getSystemService(UserManager.class);
|
||||
~~~~~~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetAccountManager() {
|
||||
lint()
|
||||
.files(
|
||||
TestFiles.java(
|
||||
"""
|
||||
package test.pkg;
|
||||
import android.content.Context;
|
||||
import android.accounts.AccountManager;
|
||||
|
||||
public class TestClass {
|
||||
public void getSystemServiceWithoutDagger(Context context) {
|
||||
AccountManager.get(context);
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
.indented(),
|
||||
*stubs
|
||||
)
|
||||
.issues(NonInjectedServiceDetector.ISSUE)
|
||||
.run()
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:7: Warning: Replace AccountManager.get() with an injected instance of AccountManager [NonInjectedService]
|
||||
AccountManager.get(context);
|
||||
~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
private val stubs = androidStubs
|
||||
|
||||
@@ -31,8 +31,6 @@ class RegisterReceiverViaContextDetectorTest : LintDetectorTest() {
|
||||
|
||||
override fun getIssues(): List<Issue> = listOf(RegisterReceiverViaContextDetector.ISSUE)
|
||||
|
||||
private val explanation = "BroadcastReceivers should be registered via BroadcastDispatcher."
|
||||
|
||||
@Test
|
||||
fun testRegisterReceiver() {
|
||||
lint()
|
||||
@@ -44,7 +42,7 @@ class RegisterReceiverViaContextDetectorTest : LintDetectorTest() {
|
||||
import android.content.Context;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
public class TestClass1 {
|
||||
public class TestClass {
|
||||
public void bind(Context context, BroadcastReceiver receiver,
|
||||
IntentFilter filter) {
|
||||
context.registerReceiver(receiver, filter, 0);
|
||||
@@ -57,8 +55,14 @@ class RegisterReceiverViaContextDetectorTest : LintDetectorTest() {
|
||||
)
|
||||
.issues(RegisterReceiverViaContextDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains(explanation)
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:9: Warning: Register BroadcastReceiver using BroadcastDispatcher instead of Context [RegisterReceiverViaContext]
|
||||
context.registerReceiver(receiver, filter, 0);
|
||||
~~~~~~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -74,7 +78,7 @@ class RegisterReceiverViaContextDetectorTest : LintDetectorTest() {
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
|
||||
public class TestClass1 {
|
||||
public class TestClass {
|
||||
public void bind(Context context, BroadcastReceiver receiver,
|
||||
IntentFilter filter, Handler handler) {
|
||||
context.registerReceiverAsUser(receiver, UserHandle.ALL, filter,
|
||||
@@ -88,8 +92,14 @@ class RegisterReceiverViaContextDetectorTest : LintDetectorTest() {
|
||||
)
|
||||
.issues(RegisterReceiverViaContextDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains(explanation)
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:11: Warning: Register BroadcastReceiver using BroadcastDispatcher instead of Context [RegisterReceiverViaContext]
|
||||
context.registerReceiverAsUser(receiver, UserHandle.ALL, filter,
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -105,7 +115,7 @@ class RegisterReceiverViaContextDetectorTest : LintDetectorTest() {
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
|
||||
public class TestClass1 {
|
||||
public class TestClass {
|
||||
public void bind(Context context, BroadcastReceiver receiver,
|
||||
IntentFilter filter, Handler handler) {
|
||||
context.registerReceiverForAllUsers(receiver, filter, "permission",
|
||||
@@ -119,8 +129,14 @@ class RegisterReceiverViaContextDetectorTest : LintDetectorTest() {
|
||||
)
|
||||
.issues(RegisterReceiverViaContextDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains(explanation)
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:11: Warning: Register BroadcastReceiver using BroadcastDispatcher instead of Context [RegisterReceiverViaContext]
|
||||
context.registerReceiverForAllUsers(receiver, filter, "permission",
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
private val stubs = androidStubs
|
||||
|
||||
@@ -44,7 +44,7 @@ class SlowUserQueryDetectorTest : LintDetectorTest() {
|
||||
package test.pkg;
|
||||
import android.app.ActivityManager;
|
||||
|
||||
public class TestClass1 {
|
||||
public class TestClass {
|
||||
public void slewlyGetCurrentUser() {
|
||||
ActivityManager.getCurrentUser();
|
||||
}
|
||||
@@ -59,10 +59,13 @@ class SlowUserQueryDetectorTest : LintDetectorTest() {
|
||||
SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
|
||||
)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains(
|
||||
"ActivityManager.getCurrentUser() is slow. " +
|
||||
"Use UserTracker.getUserId() instead."
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:6: Warning: Use UserTracker.getUserId() instead of ActivityManager.getCurrentUser() [SlowUserIdQuery]
|
||||
ActivityManager.getCurrentUser();
|
||||
~~~~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@@ -75,7 +78,7 @@ class SlowUserQueryDetectorTest : LintDetectorTest() {
|
||||
package test.pkg;
|
||||
import android.os.UserManager;
|
||||
|
||||
public class TestClass2 {
|
||||
public class TestClass {
|
||||
public void slewlyGetUserInfo(UserManager userManager) {
|
||||
userManager.getUserInfo();
|
||||
}
|
||||
@@ -90,9 +93,13 @@ class SlowUserQueryDetectorTest : LintDetectorTest() {
|
||||
SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
|
||||
)
|
||||
.run()
|
||||
.expectWarningCount(1)
|
||||
.expectContains(
|
||||
"UserManager.getUserInfo() is slow. " + "Use UserTracker.getUserInfo() instead."
|
||||
.expect(
|
||||
"""
|
||||
src/test/pkg/TestClass.java:6: Warning: Use UserTracker.getUserInfo() instead of UserManager.getUserInfo() [SlowUserInfoQuery]
|
||||
userManager.getUserInfo();
|
||||
~~~~~~~~~~~
|
||||
0 errors, 1 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@@ -105,7 +112,7 @@ class SlowUserQueryDetectorTest : LintDetectorTest() {
|
||||
package test.pkg;
|
||||
import com.android.systemui.settings.UserTracker;
|
||||
|
||||
public class TestClass3 {
|
||||
public class TestClass {
|
||||
public void quicklyGetUserId(UserTracker userTracker) {
|
||||
userTracker.getUserId();
|
||||
}
|
||||
@@ -132,7 +139,7 @@ class SlowUserQueryDetectorTest : LintDetectorTest() {
|
||||
package test.pkg;
|
||||
import com.android.systemui.settings.UserTracker;
|
||||
|
||||
public class TestClass4 {
|
||||
public class TestClass {
|
||||
public void quicklyGetUserId(UserTracker userTracker) {
|
||||
userTracker.getUserInfo();
|
||||
}
|
||||
|
||||
@@ -31,8 +31,6 @@ class SoftwareBitmapDetectorTest : LintDetectorTest() {
|
||||
|
||||
override fun getIssues(): List<Issue> = listOf(SoftwareBitmapDetector.ISSUE)
|
||||
|
||||
private val explanation = "Usage of Config.HARDWARE is highly encouraged."
|
||||
|
||||
@Test
|
||||
fun testSoftwareBitmap() {
|
||||
lint()
|
||||
@@ -41,7 +39,7 @@ class SoftwareBitmapDetectorTest : LintDetectorTest() {
|
||||
"""
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
public class TestClass1 {
|
||||
public class TestClass {
|
||||
public void test() {
|
||||
Bitmap.createBitmap(300, 300, Bitmap.Config.RGB_565);
|
||||
Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
|
||||
@@ -54,8 +52,17 @@ class SoftwareBitmapDetectorTest : LintDetectorTest() {
|
||||
)
|
||||
.issues(SoftwareBitmapDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(2)
|
||||
.expectContains(explanation)
|
||||
.expect(
|
||||
"""
|
||||
src/android/graphics/Bitmap.java:5: Warning: Replace software bitmap with Config.HARDWARE [SoftwareBitmap]
|
||||
ARGB_8888,
|
||||
~~~~~~~~~
|
||||
src/android/graphics/Bitmap.java:6: Warning: Replace software bitmap with Config.HARDWARE [SoftwareBitmap]
|
||||
RGB_565,
|
||||
~~~~~~~
|
||||
0 errors, 2 warnings
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -66,7 +73,7 @@ class SoftwareBitmapDetectorTest : LintDetectorTest() {
|
||||
"""
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
public class TestClass1 {
|
||||
public class TestClass {
|
||||
public void test() {
|
||||
Bitmap.createBitmap(300, 300, Bitmap.Config.HARDWARE);
|
||||
}
|
||||
@@ -78,7 +85,7 @@ class SoftwareBitmapDetectorTest : LintDetectorTest() {
|
||||
)
|
||||
.issues(SoftwareBitmapDetector.ISSUE)
|
||||
.run()
|
||||
.expectWarningCount(0)
|
||||
.expectClean()
|
||||
}
|
||||
|
||||
private val stubs = androidStubs
|
||||
|
||||
@@ -36,6 +36,7 @@ import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
@@ -182,6 +183,10 @@ public class TileLifecycleManager extends BroadcastReceiver implements
|
||||
setBindService(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds or unbinds to IQSService
|
||||
*/
|
||||
@WorkerThread
|
||||
public void setBindService(boolean bind) {
|
||||
if (mBound && mUnbindImmediate) {
|
||||
// If we are already bound and expecting to unbind, this means we should stay bound
|
||||
|
||||
Reference in New Issue
Block a user