diff options
| author | 2024-03-15 17:27:43 +0000 | |
|---|---|---|
| committer | 2024-03-15 17:27:43 +0000 | |
| commit | ca4cdfeeff66ac180e75fdd59b448375caa56cd5 (patch) | |
| tree | 296f2dbef284ede2f929e5377c9f8cf973294fd4 /java/src | |
| parent | 3e5527c7e60aade6609abc7e0a903ec9e128817e (diff) | |
| parent | 1a887c18ad79b5a935799f5100233db1be982ee1 (diff) | |
Merge changes Ia8dfe178,I348558b3 into main
* changes:
Correct all Kotlin formatting errors
Readability clean up for UserRepository
Diffstat (limited to 'java/src')
22 files changed, 229 insertions, 160 deletions
diff --git a/java/src/com/android/intentresolver/EnterTransitionAnimationDelegate.kt b/java/src/com/android/intentresolver/EnterTransitionAnimationDelegate.kt index b1178aa5..6a4fe65a 100644 --- a/java/src/com/android/intentresolver/EnterTransitionAnimationDelegate.kt +++ b/java/src/com/android/intentresolver/EnterTransitionAnimationDelegate.kt @@ -21,14 +21,14 @@ import androidx.activity.ComponentActivity import androidx.lifecycle.lifecycleScope import com.android.intentresolver.widget.ImagePreviewView.TransitionElementStatusCallback import com.android.internal.annotations.VisibleForTesting +import java.util.function.Supplier import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import java.util.function.Supplier /** - * A helper class to track app's readiness for the scene transition animation. - * The app is ready when both the image is laid out and the drawer offset is calculated. + * A helper class to track app's readiness for the scene transition animation. The app is ready when + * both the image is laid out and the drawer offset is calculated. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) class EnterTransitionAnimationDelegate( @@ -45,21 +45,22 @@ class EnterTransitionAnimationDelegate( activity.setEnterSharedElementCallback( object : SharedElementCallback() { override fun onMapSharedElements( - names: MutableList<String>, sharedElements: MutableMap<String, View> + names: MutableList<String>, + sharedElements: MutableMap<String, View> ) { - this@EnterTransitionAnimationDelegate.onMapSharedElements( - names, sharedElements - ) + this@EnterTransitionAnimationDelegate.onMapSharedElements(names, sharedElements) } - }) + } + ) } fun postponeTransition() { activity.postponeEnterTransition() - timeoutJob = activity.lifecycleScope.launch { - delay(activity.resources.getInteger(R.integer.config_shortAnimTime).toLong()) - onTimeout() - } + timeoutJob = + activity.lifecycleScope.launch { + delay(activity.resources.getInteger(R.integer.config_shortAnimTime).toLong()) + onTimeout() + } } private fun onTimeout() { @@ -110,8 +111,14 @@ class EnterTransitionAnimationDelegate( override fun onLayoutChange( v: View, - left: Int, top: Int, right: Int, bottom: Int, - oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int + left: Int, + top: Int, + right: Int, + bottom: Int, + oldLeft: Int, + oldTop: Int, + oldRight: Int, + oldBottom: Int ) { v.removeOnLayoutChangeListener(this) startPostponedEnterTransition() diff --git a/java/src/com/android/intentresolver/ItemRevealAnimationTracker.kt b/java/src/com/android/intentresolver/ItemRevealAnimationTracker.kt index d3e07c6b..7deb0d10 100644 --- a/java/src/com/android/intentresolver/ItemRevealAnimationTracker.kt +++ b/java/src/com/android/intentresolver/ItemRevealAnimationTracker.kt @@ -37,9 +37,7 @@ internal class ItemRevealAnimationTracker { fun animateLabel(view: View, info: TargetInfo) = animateView(view, info, labelProgress) private fun animateView(view: View, info: TargetInfo, map: MutableMap<TargetInfo, Record>) { - val record = map.getOrPut(info) { - Record() - } + val record = map.getOrPut(info) { Record() } if ((view.animation as? RevealAnimation)?.record === record) return view.clearAnimation() diff --git a/java/src/com/android/intentresolver/SecureSettings.kt b/java/src/com/android/intentresolver/SecureSettings.kt index a4853fd8..1e938895 100644 --- a/java/src/com/android/intentresolver/SecureSettings.kt +++ b/java/src/com/android/intentresolver/SecureSettings.kt @@ -19,9 +19,7 @@ package com.android.intentresolver import android.content.ContentResolver import android.provider.Settings -/** - * A proxy class for secure settings, for easier testing. - */ +/** A proxy class for secure settings, for easier testing. */ open class SecureSettings { open fun getString(resolver: ContentResolver, name: String): String? { return Settings.Secure.getString(resolver, name) diff --git a/java/src/com/android/intentresolver/contentpreview/IsHttpUri.kt b/java/src/com/android/intentresolver/contentpreview/IsHttpUri.kt index 80232537..ac002ab6 100644 --- a/java/src/com/android/intentresolver/contentpreview/IsHttpUri.kt +++ b/java/src/com/android/intentresolver/contentpreview/IsHttpUri.kt @@ -15,13 +15,16 @@ */ @file:JvmName("HttpUriMatcher") + package com.android.intentresolver.contentpreview import java.net.URI internal fun String.isHttpUri() = - kotlin.runCatching { - URI(this).scheme.takeIf { scheme -> - "http".compareTo(scheme, true) == 0 || "https".compareTo(scheme, true) == 0 + kotlin + .runCatching { + URI(this).scheme.takeIf { scheme -> + "http".compareTo(scheme, true) == 0 || "https".compareTo(scheme, true) == 0 + } } - }.getOrNull() != null + .getOrNull() != null diff --git a/java/src/com/android/intentresolver/inject/SystemServices.kt b/java/src/com/android/intentresolver/inject/SystemServices.kt index 069c926c..9e7c67b6 100644 --- a/java/src/com/android/intentresolver/inject/SystemServices.kt +++ b/java/src/com/android/intentresolver/inject/SystemServices.kt @@ -103,7 +103,8 @@ class UserManagerModule { @Provides fun userManager(@ApplicationContext ctx: Context): UserManager = ctx.requireSystemService() - @Provides fun scopedUserManager(ctx: UserScopedContext): UserScopedService<UserManager> { + @Provides + fun scopedUserManager(ctx: UserScopedContext): UserScopedService<UserManager> { return UserScopedServiceImpl(ctx, UserManager::class) } } diff --git a/java/src/com/android/intentresolver/shortcuts/AppPredictorFactory.kt b/java/src/com/android/intentresolver/shortcuts/AppPredictorFactory.kt index e544e064..c7bd0336 100644 --- a/java/src/com/android/intentresolver/shortcuts/AppPredictorFactory.kt +++ b/java/src/com/android/intentresolver/shortcuts/AppPredictorFactory.kt @@ -31,12 +31,13 @@ private const val SHARED_TEXT_KEY = "shared_text" /** * A factory to create an AppPredictor instance for a profile, if available. + * * @param context, application context - * @param sharedText, a shared text associated with the Chooser's target intent - * (see [android.content.Intent.EXTRA_TEXT]). - * Will be mapped to app predictor's "shared_text" parameter. - * @param targetIntentFilter, an IntentFilter to match direct share targets against. - * Will be mapped app predictor's "intent_filter" parameter. + * @param sharedText, a shared text associated with the Chooser's target intent (see + * [android.content.Intent.EXTRA_TEXT]). Will be mapped to app predictor's "shared_text" + * parameter. + * @param targetIntentFilter, an IntentFilter to match direct share targets against. Will be mapped + * app predictor's "intent_filter" parameter. */ class AppPredictorFactory( private val context: Context, @@ -50,16 +51,19 @@ class AppPredictorFactory( fun create(userHandle: UserHandle): AppPredictor? { if (!appPredictionAvailable) return null val contextAsUser = context.createContextAsUser(userHandle, 0 /* flags */) - val extras = Bundle().apply { - putParcelable(APP_PREDICTION_INTENT_FILTER_KEY, targetIntentFilter) - putString(SHARED_TEXT_KEY, sharedText) - } - val appPredictionContext = AppPredictionContext.Builder(contextAsUser) - .setUiSurface(APP_PREDICTION_SHARE_UI_SURFACE) - .setPredictedTargetCount(APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT) - .setExtras(extras) - .build() - return contextAsUser.getSystemService(AppPredictionManager::class.java) + val extras = + Bundle().apply { + putParcelable(APP_PREDICTION_INTENT_FILTER_KEY, targetIntentFilter) + putString(SHARED_TEXT_KEY, sharedText) + } + val appPredictionContext = + AppPredictionContext.Builder(contextAsUser) + .setUiSurface(APP_PREDICTION_SHARE_UI_SURFACE) + .setPredictedTargetCount(APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT) + .setExtras(extras) + .build() + return contextAsUser + .getSystemService(AppPredictionManager::class.java) ?.createAppPredictionSession(appPredictionContext) } } diff --git a/java/src/com/android/intentresolver/util/Flow.kt b/java/src/com/android/intentresolver/util/Flow.kt index 1155b9fe..598379f3 100644 --- a/java/src/com/android/intentresolver/util/Flow.kt +++ b/java/src/com/android/intentresolver/util/Flow.kt @@ -31,7 +31,6 @@ import kotlinx.coroutines.launch * latest value is emitted. * * Example: - * * ```kotlin * flow { * emit(1) // t=0ms @@ -70,10 +69,11 @@ fun <T> Flow<T>.throttle(periodMs: Long): Flow<T> = channelFlow { // We create delayJob to allow cancellation during the delay period delayJob = launch { delay(timeUntilNextEmit) - sendJob = outerScope.launch(start = CoroutineStart.UNDISPATCHED) { - send(it) - previousEmitTimeMs = SystemClock.elapsedRealtime() - } + sendJob = + outerScope.launch(start = CoroutineStart.UNDISPATCHED) { + send(it) + previousEmitTimeMs = SystemClock.elapsedRealtime() + } } } else { send(it) diff --git a/java/src/com/android/intentresolver/v2/annotation/JavaInterop.kt b/java/src/com/android/intentresolver/v2/annotation/JavaInterop.kt index 15c5018a..a813358e 100644 --- a/java/src/com/android/intentresolver/v2/annotation/JavaInterop.kt +++ b/java/src/com/android/intentresolver/v2/annotation/JavaInterop.kt @@ -21,6 +21,8 @@ package com.android.intentresolver.v2.annotation * * The goal is to prevent usage from Kotlin when a more idiomatic alternative is available. */ -@RequiresOptIn("This is a a property, function or class specifically supporting Java " + - "interoperability. Usage from Kotlin should be limited to interactions with Java.") +@RequiresOptIn( + "This is a a property, function or class specifically supporting Java " + + "interoperability. Usage from Kotlin should be limited to interactions with Java." +) annotation class JavaInterop diff --git a/java/src/com/android/intentresolver/v2/data/repository/UserRepository.kt b/java/src/com/android/intentresolver/v2/data/repository/UserRepository.kt index 4c42e2cd..40672249 100644 --- a/java/src/com/android/intentresolver/v2/data/repository/UserRepository.kt +++ b/java/src/com/android/intentresolver/v2/data/repository/UserRepository.kt @@ -28,6 +28,7 @@ import android.content.Intent.EXTRA_QUIET_MODE import android.content.Intent.EXTRA_USER import android.content.IntentFilter import android.content.pm.UserInfo +import android.os.Build import android.os.UserHandle import android.os.UserManager import android.util.Log @@ -36,7 +37,6 @@ import com.android.intentresolver.inject.Background import com.android.intentresolver.inject.Main import com.android.intentresolver.inject.ProfileParent import com.android.intentresolver.v2.data.broadcastFlow -import com.android.intentresolver.v2.data.repository.UserRepositoryImpl.UserEvent import com.android.intentresolver.v2.shared.model.User import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject @@ -73,7 +73,7 @@ interface UserRepository { * stopping a profile user (along with their many associated processes). * * If successful, the change will be applied after the call returns and can be observed using - * [UserRepository.isAvailable] for the given user. + * [UserRepository.availability] for the given user. * * No actions are taken if the user is already in requested state. * @@ -84,9 +84,9 @@ interface UserRepository { private const val TAG = "UserRepository" -private data class UserWithState(val user: User, val available: Boolean) +internal data class UserWithState(val user: User, val available: Boolean) -private typealias UserStates = List<UserWithState> +internal typealias UserStates = List<UserWithState> /** Tracks and publishes state for the parent user and associated profiles. */ class UserRepositoryImpl @@ -114,13 +114,21 @@ constructor( background ) - data class UserEvent(val action: String, val user: UserHandle, val quietMode: Boolean = false) + private fun debugLog(msg: () -> String) { + if (Build.IS_USERDEBUG || Build.IS_ENG) { + Log.d(TAG, msg()) + } + } + + private fun errorLog(msg: String, caught: Throwable? = null) { + Log.e(TAG, msg, caught) + } /** * An exception which indicates that an inconsistency exists between the user state map and the * rest of the system. */ - internal class UserStateException( + private class UserStateException( override val message: String, val event: UserEvent, override val cause: Throwable? = null @@ -129,35 +137,34 @@ constructor( private val sharingScope = CoroutineScope(scope.coroutineContext + backgroundDispatcher) private val usersWithState: Flow<UserStates> = userEvents - .onStart { emit(UserEvent(INITIALIZE, profileParent)) } - .onEach { Log.i(TAG, "userEvent: $it") } - .runningFold<UserEvent, UserStates>(emptyList()) { users, event -> - try { - // Handle an action by performing some operation, then returning a new map - when (event.action) { - INITIALIZE -> createNewUserStates(profileParent) - ACTION_PROFILE_ADDED -> handleProfileAdded(event, users) - ACTION_PROFILE_REMOVED -> handleProfileRemoved(event, users) - ACTION_MANAGED_PROFILE_UNAVAILABLE, - ACTION_MANAGED_PROFILE_AVAILABLE, - ACTION_PROFILE_AVAILABLE, - ACTION_PROFILE_UNAVAILABLE -> handleAvailability(event, users) - else -> { - Log.w(TAG, "Unhandled event: $event)") - users - } - } - } catch (e: UserStateException) { - Log.e(TAG, "An error occurred handling an event: ${e.event}", e) - Log.e(TAG, "Attempting to recover...") - createNewUserStates(profileParent) - } - } + .onStart { emit(Initialize) } + .onEach { debugLog { "userEvent: $it" } } + .runningFold(emptyList(), ::handleEvent) .distinctUntilChanged() - .onEach { Log.i(TAG, "userStateList: $it") } + .onEach { debugLog { "userStateList: $it" } } .stateIn(sharingScope, SharingStarted.Eagerly, emptyList()) .filterNot { it.isEmpty() } + private suspend fun handleEvent(users: UserStates, event: UserEvent): UserStates { + return try { + // Handle an action by performing some operation, then returning a new map + when (event) { + is Initialize -> createNewUserStates(profileParent) + is ProfileAdded -> handleProfileAdded(event, users) + is ProfileRemoved -> handleProfileRemoved(event, users) + is AvailabilityChange -> handleAvailability(event, users) + is UnknownEvent -> { + debugLog { "Unhandled event: $event)" } + users + } + } + } catch (e: UserStateException) { + errorLog("An error occurred handling an event: ${e.event}") + errorLog("Attempting to recover...", e) + createNewUserStates(profileParent) + } + } + override val users: Flow<List<User>> = usersWithState.map { userStateMap -> userStateMap.map { it.user } }.distinctUntilChanged() @@ -168,7 +175,7 @@ constructor( override suspend fun requestState(user: User, available: Boolean) { return withContext(backgroundDispatcher) { - Log.i(TAG, "requestQuietModeEnabled: ${!available} for user $user") + debugLog { "requestQuietModeEnabled: ${!available} for user $user" } userManager.requestQuietModeEnabled(/* enableQuietMode = */ !available, user.handle) } } @@ -176,28 +183,28 @@ constructor( private fun List<UserWithState>.update(handle: UserHandle, user: UserWithState) = filter { it.user.id != handle.identifier } + user - private fun handleAvailability(event: UserEvent, current: UserStates): UserStates { + private fun handleAvailability(event: AvailabilityChange, current: UserStates): UserStates { val userEntry = current.firstOrNull { it.user.id == event.user.identifier } ?: throw UserStateException("User was not present in the map", event) return current.update(event.user, userEntry.copy(available = !event.quietMode)) } - private fun handleProfileRemoved(event: UserEvent, current: UserStates): UserStates { + private fun handleProfileRemoved(event: ProfileRemoved, current: UserStates): UserStates { if (!current.any { it.user.id == event.user.identifier }) { throw UserStateException("User was not present in the map", event) } return current.filter { it.user.id != event.user.identifier } } - private suspend fun handleProfileAdded(event: UserEvent, current: UserStates): UserStates { + private suspend fun handleProfileAdded(event: ProfileAdded, current: UserStates): UserStates { val user = try { requireNotNull(readUser(event.user)) } catch (e: Exception) { throw UserStateException("Failed to read user from UserManager", event, e) } - return current + UserWithState(user, !event.quietMode) + return current + UserWithState(user, true) } private suspend fun createNewUserStates(user: UserHandle): UserStates { @@ -224,29 +231,64 @@ constructor( } } +/** A Model representing changes to profiles and availability */ +sealed interface UserEvent + +/** Used as a an initial value to trigger a fetch of all profile data. */ +data object Initialize : UserEvent + +/** A profile was added to the profile group. */ +data class ProfileAdded( + /** The handle for the added profile. */ + val user: UserHandle, +) : UserEvent + +/** A profile was removed from the profile group. */ +data class ProfileRemoved( + /** The handle for the removed profile. */ + val user: UserHandle, +) : UserEvent + +/** A profile has changed availability. */ +data class AvailabilityChange( + /** THe handle for the profile with availability change. */ + val user: UserHandle, + /** The new quietMode state. */ + val quietMode: Boolean = false, +) : UserEvent + +/** An unhandled event, logged and ignored. */ +data class UnknownEvent( + /** The broadcast intent action received */ + val action: String?, +) : UserEvent + /** Used with [broadcastFlow] to transform a UserManager broadcast action into a [UserEvent]. */ -private fun Intent.toUserEvent(): UserEvent? { +private fun Intent.toUserEvent(): UserEvent { val action = action val user = extras?.getParcelable(EXTRA_USER, UserHandle::class.java) - val quietMode = extras?.getBoolean(EXTRA_QUIET_MODE, false) ?: false - return if (user == null || action == null) { - null - } else { - UserEvent(action, user, quietMode) + val quietMode = extras?.getBoolean(EXTRA_QUIET_MODE, false) + return when (action) { + ACTION_PROFILE_ADDED -> ProfileAdded(requireNotNull(user)) + ACTION_PROFILE_REMOVED -> ProfileRemoved(requireNotNull(user)) + ACTION_MANAGED_PROFILE_UNAVAILABLE, + ACTION_MANAGED_PROFILE_AVAILABLE, + ACTION_PROFILE_AVAILABLE, + ACTION_PROFILE_UNAVAILABLE -> + AvailabilityChange(requireNotNull(user), requireNotNull(quietMode)) + else -> UnknownEvent(action) } } -const val INITIALIZE = "INITIALIZE" - private fun createFilter(actions: Iterable<String>): IntentFilter { return IntentFilter().apply { actions.forEach(::addAction) } } -private fun UserInfo?.isAvailable(): Boolean { +internal fun UserInfo?.isAvailable(): Boolean { return this?.isQuietModeEnabled != true } -private fun userBroadcastFlow(context: Context, profileParent: UserHandle): Flow<UserEvent> { +internal fun userBroadcastFlow(context: Context, profileParent: UserHandle): Flow<UserEvent> { val userActions = setOf( ACTION_PROFILE_ADDED, diff --git a/java/src/com/android/intentresolver/v2/data/repository/UserScopedService.kt b/java/src/com/android/intentresolver/v2/data/repository/UserScopedService.kt index 07903a7b..507979a0 100644 --- a/java/src/com/android/intentresolver/v2/data/repository/UserScopedService.kt +++ b/java/src/com/android/intentresolver/v2/data/repository/UserScopedService.kt @@ -76,10 +76,8 @@ class UserScopedContext @Inject constructor(private val applicationContext: Cont } /** Returns a cache of service instances, distinct by user */ -class UserScopedServiceImpl<T : Any>( - contexts: UserScopedContext, - serviceType: KClass<T> -): UserScopedService<T> { +class UserScopedServiceImpl<T : Any>(contexts: UserScopedContext, serviceType: KClass<T>) : + UserScopedService<T> { private val instances = object : LruCache<UserHandle, T>(8) { override fun create(key: UserHandle): T { diff --git a/java/src/com/android/intentresolver/v2/domain/interactor/UserInteractor.kt b/java/src/com/android/intentresolver/v2/domain/interactor/UserInteractor.kt index 72b604c2..69374f88 100644 --- a/java/src/com/android/intentresolver/v2/domain/interactor/UserInteractor.kt +++ b/java/src/com/android/intentresolver/v2/domain/interactor/UserInteractor.kt @@ -71,9 +71,7 @@ constructor( */ val availability: Flow<Map<Profile, Boolean>> = combine(profiles, userRepository.availability) { profiles, availability -> - profiles.associateWith { - availability.getOrDefault(it.primary, false) - } + profiles.associateWith { availability.getOrDefault(it.primary, false) } } /** diff --git a/java/src/com/android/intentresolver/v2/platform/AppPredictionModule.kt b/java/src/com/android/intentresolver/v2/platform/AppPredictionModule.kt index 9ca9d871..090fab6b 100644 --- a/java/src/com/android/intentresolver/v2/platform/AppPredictionModule.kt +++ b/java/src/com/android/intentresolver/v2/platform/AppPredictionModule.kt @@ -18,7 +18,6 @@ package com.android.intentresolver.v2.platform import android.content.pm.PackageManager import dagger.Module import dagger.Provides -import dagger.Reusable import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import javax.inject.Qualifier @@ -33,13 +32,11 @@ annotation class AppPredictionAvailable @InstallIn(SingletonComponent::class) object AppPredictionModule { - /** - * Eventually replaced with: Optional<AppPredictionRepository>, etc. - */ + /** Eventually replaced with: Optional<AppPredictionRepository>, etc. */ @Provides @Singleton @AppPredictionAvailable fun isAppPredictionAvailable(packageManager: PackageManager): Boolean { return packageManager.appPredictionServicePackageName != null } -}
\ No newline at end of file +} diff --git a/java/src/com/android/intentresolver/v2/ui/ProfilePagerResources.kt b/java/src/com/android/intentresolver/v2/ui/ProfilePagerResources.kt index 1cd72ba5..ca7ae0fc 100644 --- a/java/src/com/android/intentresolver/v2/ui/ProfilePagerResources.kt +++ b/java/src/com/android/intentresolver/v2/ui/ProfilePagerResources.kt @@ -17,11 +17,11 @@ package com.android.intentresolver.v2.ui import android.content.res.Resources +import com.android.intentresolver.R import com.android.intentresolver.inject.ApplicationOwned import com.android.intentresolver.v2.data.repository.DevicePolicyResources import com.android.intentresolver.v2.shared.model.Profile import javax.inject.Inject -import com.android.intentresolver.R class ProfilePagerResources @Inject @@ -50,4 +50,4 @@ constructor( Profile.Type.PRIVATE -> privateTabAccessibilityLabel } } -}
\ No newline at end of file +} diff --git a/java/src/com/android/intentresolver/v2/ui/ShortcutPolicyModule.kt b/java/src/com/android/intentresolver/v2/ui/ShortcutPolicyModule.kt index 9ed5f9dd..5e098cd5 100644 --- a/java/src/com/android/intentresolver/v2/ui/ShortcutPolicyModule.kt +++ b/java/src/com/android/intentresolver/v2/ui/ShortcutPolicyModule.kt @@ -29,11 +29,19 @@ import javax.inject.Qualifier import javax.inject.Singleton @Qualifier -@MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class AppShortcutLimit +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class AppShortcutLimit + @Qualifier -@MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class EnforceShortcutLimit +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class EnforceShortcutLimit + @Qualifier -@MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class ShortcutRowLimit +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class ShortcutRowLimit @Module @InstallIn(SingletonComponent::class) @@ -41,8 +49,8 @@ object ShortcutPolicyModule { /** * Defines the limit for the number of shortcut targets provided for any single app. * - * This value applies to both results from Shortcut-service and app-provided targets on - * a per-package basis. + * This value applies to both results from Shortcut-service and app-provided targets on a + * per-package basis. */ @Provides @Singleton @@ -64,8 +72,11 @@ object ShortcutPolicyModule { @Singleton @EnforceShortcutLimit fun applyShortcutLimit(): Boolean { - return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI, true) + return DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI, + true + ) } /** @@ -80,4 +91,4 @@ object ShortcutPolicyModule { fun shortcutRowLimit(@ApplicationOwned resources: Resources): Int { return resources.getInteger(R.integer.config_chooser_max_targets_per_row) } -}
\ No newline at end of file +} diff --git a/java/src/com/android/intentresolver/v2/ui/model/ResolverRequest.kt b/java/src/com/android/intentresolver/v2/ui/model/ResolverRequest.kt index a4f74ca9..44010caf 100644 --- a/java/src/com/android/intentresolver/v2/ui/model/ResolverRequest.kt +++ b/java/src/com/android/intentresolver/v2/ui/model/ResolverRequest.kt @@ -19,8 +19,8 @@ package com.android.intentresolver.v2.ui.model import android.content.Intent import android.content.pm.ResolveInfo import android.os.UserHandle -import com.android.intentresolver.v2.shared.model.Profile import com.android.intentresolver.v2.ext.isHomeIntent +import com.android.intentresolver.v2.shared.model.Profile /** All of the things that are consumed from an incoming Intent Resolution request (+Extras). */ data class ResolverRequest( diff --git a/java/src/com/android/intentresolver/v2/validation/types/IntentOrUri.kt b/java/src/com/android/intentresolver/v2/validation/types/IntentOrUri.kt index 050bd895..fc51ba1e 100644 --- a/java/src/com/android/intentresolver/v2/validation/types/IntentOrUri.kt +++ b/java/src/com/android/intentresolver/v2/validation/types/IntentOrUri.kt @@ -31,7 +31,6 @@ class IntentOrUri(override val key: String) : Validator<Intent> { source: (String) -> Any?, importance: Importance ): ValidationResult<Intent> { - return when (val value = source(key)) { // An intent, return it. is Intent -> Valid(value) @@ -41,10 +40,11 @@ class IntentOrUri(override val key: String) : Validator<Intent> { is Uri -> Valid(Intent.parseUri(value.toString(), Intent.URI_INTENT_SCHEME)) // No value present. - null -> when (importance) { - Importance.WARNING -> Invalid() // No warnings if optional, but missing - Importance.CRITICAL -> Invalid(NoValue(key, importance, Intent::class)) - } + null -> + when (importance) { + Importance.WARNING -> Invalid() // No warnings if optional, but missing + Importance.CRITICAL -> Invalid(NoValue(key, importance, Intent::class)) + } // Some other type. else -> { diff --git a/java/src/com/android/intentresolver/v2/validation/types/ParceledArray.kt b/java/src/com/android/intentresolver/v2/validation/types/ParceledArray.kt index 78adfd36..b68d972f 100644 --- a/java/src/com/android/intentresolver/v2/validation/types/ParceledArray.kt +++ b/java/src/com/android/intentresolver/v2/validation/types/ParceledArray.kt @@ -15,7 +15,6 @@ */ package com.android.intentresolver.v2.validation.types -import android.content.Intent import com.android.intentresolver.v2.validation.Importance import com.android.intentresolver.v2.validation.Invalid import com.android.intentresolver.v2.validation.NoValue @@ -36,13 +35,13 @@ class ParceledArray<T : Any>( source: (String) -> Any?, importance: Importance ): ValidationResult<List<T>> { - return when (val value: Any? = source(key)) { // No value present. - null -> when (importance) { - Importance.WARNING -> Invalid() // No warnings if optional, but missing - Importance.CRITICAL -> Invalid(NoValue(key, importance, elementType)) - } + null -> + when (importance) { + Importance.WARNING -> Invalid() // No warnings if optional, but missing + Importance.CRITICAL -> Invalid(NoValue(key, importance, elementType)) + } // A parcel does not transfer the element type information for parcelable // arrays. This leads to a restored type of Array<Parcelable>, which is // incompatible with Array<T : Parcelable>. diff --git a/java/src/com/android/intentresolver/v2/validation/types/SimpleValue.kt b/java/src/com/android/intentresolver/v2/validation/types/SimpleValue.kt index 0105541d..0badebc4 100644 --- a/java/src/com/android/intentresolver/v2/validation/types/SimpleValue.kt +++ b/java/src/com/android/intentresolver/v2/validation/types/SimpleValue.kt @@ -37,21 +37,24 @@ class SimpleValue<T : Any>( expected.isInstance(value) -> return Valid(expected.cast(value)) // No value is present. - value == null -> when (importance) { - Importance.WARNING -> Invalid() // No warnings if optional, but missing - Importance.CRITICAL -> Invalid(NoValue(key, importance, expected)) - } + value == null -> + when (importance) { + Importance.WARNING -> Invalid() // No warnings if optional, but missing + Importance.CRITICAL -> Invalid(NoValue(key, importance, expected)) + } // The value is some other type. else -> - Invalid(listOf( - ValueIsWrongType( - key, - importance, - actualType = value::class, - allowedTypes = listOf(expected) + Invalid( + listOf( + ValueIsWrongType( + key, + importance, + actualType = value::class, + allowedTypes = listOf(expected) + ) ) - )) + ) } } } diff --git a/java/src/com/android/intentresolver/widget/ActionRow.kt b/java/src/com/android/intentresolver/widget/ActionRow.kt index 6764d3ae..c1f03751 100644 --- a/java/src/com/android/intentresolver/widget/ActionRow.kt +++ b/java/src/com/android/intentresolver/widget/ActionRow.kt @@ -22,7 +22,9 @@ import android.graphics.drawable.Drawable interface ActionRow { fun setActions(actions: List<Action>) - class Action @JvmOverloads constructor( + class Action + @JvmOverloads + constructor( // TODO: apparently, IDs set to this field are used in unit tests only; evaluate whether we // get rid of them val id: Int = ID_NULL, diff --git a/java/src/com/android/intentresolver/widget/ImagePreviewView.kt b/java/src/com/android/intentresolver/widget/ImagePreviewView.kt index 3f0458ee..55418c49 100644 --- a/java/src/com/android/intentresolver/widget/ImagePreviewView.kt +++ b/java/src/com/android/intentresolver/widget/ImagePreviewView.kt @@ -24,15 +24,16 @@ interface ImagePreviewView { /** * [ImagePreviewView] progressively prepares views for shared element transition and reports - * each successful preparation with [onTransitionElementReady] call followed by - * closing [onAllTransitionElementsReady] invocation. Thus the overall invocation pattern is - * zero or more [onTransitionElementReady] calls followed by the final - * [onAllTransitionElementsReady] call. + * each successful preparation with [onTransitionElementReady] call followed by closing + * [onAllTransitionElementsReady] invocation. Thus the overall invocation pattern is zero or + * more [onTransitionElementReady] calls followed by the final [onAllTransitionElementsReady] + * call. */ interface TransitionElementStatusCallback { /** - * Invoked when a view for a shared transition animation element is ready i.e. the image - * is loaded and the view is laid out. + * Invoked when a view for a shared transition animation element is ready i.e. the image is + * loaded and the view is laid out. + * * @param name shared element name. */ fun onTransitionElementReady(name: String) diff --git a/java/src/com/android/intentresolver/widget/RecyclerViewExtensions.kt b/java/src/com/android/intentresolver/widget/RecyclerViewExtensions.kt index a7906001..a8aa633b 100644 --- a/java/src/com/android/intentresolver/widget/RecyclerViewExtensions.kt +++ b/java/src/com/android/intentresolver/widget/RecyclerViewExtensions.kt @@ -26,10 +26,10 @@ internal val RecyclerView.areAllChildrenVisible: Boolean val first = getChildAt(0) val last = getChildAt(count - 1) val itemCount = adapter?.itemCount ?: 0 - return getChildAdapterPosition(first) == 0 - && getChildAdapterPosition(last) == itemCount - 1 - && isFullyVisible(first) - && isFullyVisible(last) + return getChildAdapterPosition(first) == 0 && + getChildAdapterPosition(last) == itemCount - 1 && + isFullyVisible(first) && + isFullyVisible(last) } private fun RecyclerView.isFullyVisible(view: View): Boolean = diff --git a/java/src/com/android/intentresolver/widget/ViewExtensions.kt b/java/src/com/android/intentresolver/widget/ViewExtensions.kt index 11b7c146..d19933f5 100644 --- a/java/src/com/android/intentresolver/widget/ViewExtensions.kt +++ b/java/src/com/android/intentresolver/widget/ViewExtensions.kt @@ -19,21 +19,26 @@ package com.android.intentresolver.widget import android.util.Log import android.view.View import androidx.core.view.OneShotPreDrawListener -import kotlinx.coroutines.suspendCancellableCoroutine import java.util.concurrent.atomic.AtomicBoolean +import kotlinx.coroutines.suspendCancellableCoroutine internal suspend fun View.waitForPreDraw(): Unit = suspendCancellableCoroutine { continuation -> val isResumed = AtomicBoolean(false) - val callback = OneShotPreDrawListener.add( - this, - Runnable { - if (isResumed.compareAndSet(false, true)) { - continuation.resumeWith(Result.success(Unit)) - } else { - // it's not really expected but in some unknown corner-case let's not crash - Log.e("waitForPreDraw", "An attempt to resume a completed coroutine", Exception()) + val callback = + OneShotPreDrawListener.add( + this, + Runnable { + if (isResumed.compareAndSet(false, true)) { + continuation.resumeWith(Result.success(Unit)) + } else { + // it's not really expected but in some unknown corner-case let's not crash + Log.e( + "waitForPreDraw", + "An attempt to resume a completed coroutine", + Exception() + ) + } } - } - ) + ) continuation.invokeOnCancellation { callback.removeListener() } } |