summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
author Andrey Epin <ayepin@google.com> 2023-05-09 16:21:03 -0700
committer Andrey Epin <ayepin@google.com> 2023-05-10 12:28:13 -0700
commitc9b17c7ea3596aa2698149c592e623a3a492b70a (patch)
tree72d72501f1a8ceac4ad45c2ff6e6899a6db21e5f /java
parentb6db5913d41b01476ef027d7e40f032f4f3c4ed9 (diff)
Add traces for shortcuts, app targets and icons
Add traces and extra logging for shortcuts fetching, app targets resolution and shortcut and app icons loading. Bug: 280653893 Test: main functinality smoke testing; test traces collected. Change-Id: I68fd624fb0e747947bf9f0d704adec7697a190d0
Diffstat (limited to 'java')
-rw-r--r--java/src/com/android/intentresolver/ChooserActivity.java9
-rw-r--r--java/src/com/android/intentresolver/ChooserListAdapter.java3
-rw-r--r--java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java17
-rw-r--r--java/src/com/android/intentresolver/ResolverListAdapter.java3
-rw-r--r--java/src/com/android/intentresolver/measurements/Tracer.kt110
-rw-r--r--java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt215
6 files changed, 252 insertions, 105 deletions
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java
index 84e14d72..ca29b6f0 100644
--- a/java/src/com/android/intentresolver/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/ChooserActivity.java
@@ -1550,6 +1550,10 @@ public class ChooserActivity extends ResolverActivity implements
}
if (rebuildComplete) {
+ long duration = Tracer.INSTANCE.endAppTargetLoadingSection(listAdapter.getUserHandle());
+ if (duration >= 0) {
+ Log.d(TAG, "app target loading time " + duration + " ms");
+ }
addCallerChooserTargets();
getChooserActivityLogger().logSharesheetAppLoadComplete();
maybeQueryAdditionalPostProcessingTargets(chooserListAdapter);
@@ -1591,7 +1595,10 @@ public class ChooserActivity extends ResolverActivity implements
}
if (mMultiProfilePagerAdapter.getActiveListAdapter() == adapter) {
- Tracer.INSTANCE.endLaunchToShortcutTrace();
+ long duration = Tracer.INSTANCE.endLaunchToShortcutTrace();
+ if (duration >= 0) {
+ Log.d(TAG, "stat to first shortcut time: " + duration + " ms");
+ }
}
logDirectShareTargetReceived(userHandle);
sendVoiceChoicesIfNeeded();
diff --git a/java/src/com/android/intentresolver/ChooserListAdapter.java b/java/src/com/android/intentresolver/ChooserListAdapter.java
index ebbf5515..c20af20c 100644
--- a/java/src/com/android/intentresolver/ChooserListAdapter.java
+++ b/java/src/com/android/intentresolver/ChooserListAdapter.java
@@ -676,6 +676,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
@Override
protected Drawable doInBackground(Void... voids) {
Drawable drawable;
+ Trace.beginSection("shortcut-icon");
try {
drawable = getChooserTargetIconDrawable(
mContext,
@@ -688,6 +689,8 @@ public class ChooserListAdapter extends ResolverListAdapter {
+ mTargetInfo.getChooserTargetComponentName(),
e);
drawable = loadIconPlaceholder();
+ } finally {
+ Trace.endSection();
}
return drawable;
}
diff --git a/java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java
index 9c096fd2..da7dc998 100644
--- a/java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java
@@ -26,6 +26,7 @@ import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.PagerAdapter;
import com.android.intentresolver.grid.ChooserGridAdapter;
+import com.android.intentresolver.measurements.Tracer;
import com.android.internal.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
@@ -130,6 +131,22 @@ public class ChooserMultiProfilePagerAdapter extends GenericMultiProfilePagerAda
return rootView;
}
+ @Override
+ boolean rebuildActiveTab(boolean doPostProcessing) {
+ if (doPostProcessing) {
+ Tracer.INSTANCE.beginAppTargetLoadingSection(getActiveListAdapter().getUserHandle());
+ }
+ return super.rebuildActiveTab(doPostProcessing);
+ }
+
+ @Override
+ boolean rebuildInactiveTab(boolean doPostProcessing) {
+ if (getItemCount() != 1 && doPostProcessing) {
+ Tracer.INSTANCE.beginAppTargetLoadingSection(getInactiveListAdapter().getUserHandle());
+ }
+ return super.rebuildInactiveTab(doPostProcessing);
+ }
+
private static class BottomPaddingOverrideSupplier implements Supplier<Optional<Integer>> {
private final Context mContext;
private int mBottomOffset;
diff --git a/java/src/com/android/intentresolver/ResolverListAdapter.java b/java/src/com/android/intentresolver/ResolverListAdapter.java
index fb7641b3..a5fdd320 100644
--- a/java/src/com/android/intentresolver/ResolverListAdapter.java
+++ b/java/src/com/android/intentresolver/ResolverListAdapter.java
@@ -1034,12 +1034,15 @@ public class ResolverListAdapter extends BaseAdapter {
@Override
protected Drawable doInBackground(Void... params) {
+ Trace.beginSection("app-icon");
try {
return loadIconForResolveInfo(mResolveInfo);
} catch (Exception e) {
ComponentName componentName = mDisplayResolveInfo.getResolvedComponentName();
Log.e(TAG, "Failed to load app icon for " + componentName, e);
return loadIconPlaceholder();
+ } finally {
+ Trace.endSection();
}
}
diff --git a/java/src/com/android/intentresolver/measurements/Tracer.kt b/java/src/com/android/intentresolver/measurements/Tracer.kt
index f7e01879..5f69932a 100644
--- a/java/src/com/android/intentresolver/measurements/Tracer.kt
+++ b/java/src/com/android/intentresolver/measurements/Tracer.kt
@@ -18,14 +18,20 @@ package com.android.intentresolver.measurements
import android.os.SystemClock
import android.os.Trace
-import android.util.Log
+import android.os.UserHandle
+import android.util.SparseArray
+import androidx.annotation.GuardedBy
+import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicLong
-private const val TAG = "Tracer"
private const val SECTION_LAUNCH_TO_SHORTCUT = "launch-to-shortcut"
+private const val SECTION_APP_PREDICTOR_PREFIX = "app-predictor-"
+private const val SECTION_APP_TARGET_PREFIX = "app-target-"
object Tracer {
private val launchToFirstShortcut = AtomicLong(-1L)
+ private val nextId = AtomicInteger(0)
+ @GuardedBy("self") private val profileRecords = SparseArray<ProfileRecord>()
fun markLaunched() {
if (launchToFirstShortcut.compareAndSet(-1, elapsedTimeNow())) {
@@ -33,18 +39,112 @@ object Tracer {
}
}
- fun endLaunchToShortcutTrace() {
+ fun endLaunchToShortcutTrace(): Long {
val time = elapsedTimeNow()
val startTime = launchToFirstShortcut.get()
- if (startTime >= 0 && launchToFirstShortcut.compareAndSet(startTime, -1L)) {
+ return if (startTime >= 0 && launchToFirstShortcut.compareAndSet(startTime, -1L)) {
Trace.endAsyncSection(SECTION_LAUNCH_TO_SHORTCUT, 1)
- Log.d(TAG, "stat to first shortcut time: ${time - startTime} ms")
+ time - startTime
+ } else {
+ -1L
}
}
+ /**
+ * Begin shortcuts request tracing. The logic is based on an assumption that each request for
+ * shortcuts update is followed by at least one response. Note, that it is not always measure
+ * the request duration correctly as in the case of a two overlapping requests when the second
+ * requests starts and ends while the first is running, the end of the second request will be
+ * attributed to the first. This is tolerable as this still represents the visible to the user
+ * app's behavior and expected to be quite rare.
+ */
+ fun beginAppPredictorQueryTrace(userHandle: UserHandle) {
+ val queue = getUserShortcutRequestQueue(userHandle, createIfMissing = true) ?: return
+ val startTime = elapsedTimeNow()
+ val id = nextId.getAndIncrement()
+ val sectionName = userHandle.toAppPredictorSectionName()
+ synchronized(queue) {
+ Trace.beginAsyncSection(sectionName, id)
+ queue.addFirst(longArrayOf(startTime, id.toLong()))
+ }
+ }
+
+ /**
+ * End shortcut request tracing, see [beginAppPredictorQueryTrace].
+ *
+ * @return request duration is milliseconds.
+ */
+ fun endAppPredictorQueryTrace(userHandle: UserHandle): Long {
+ val queue = getUserShortcutRequestQueue(userHandle, createIfMissing = false) ?: return -1L
+ val endTime = elapsedTimeNow()
+ val sectionName = userHandle.toAppPredictorSectionName()
+ return synchronized(queue) { queue.removeLastOrNull() }
+ ?.let { record ->
+ Trace.endAsyncSection(sectionName, record[1].toInt())
+ endTime - record[0]
+ }
+ ?: -1L
+ }
+
+ /**
+ * Trace app target loading section per profile. If there's already an active section, it will
+ * be ended an a new section started.
+ */
+ fun beginAppTargetLoadingSection(userHandle: UserHandle) {
+ val profile = getProfileRecord(userHandle, createIfMissing = true) ?: return
+ val sectionName = userHandle.toAppTargetSectionName()
+ val time = elapsedTimeNow()
+ synchronized(profile) {
+ if (profile.appTargetLoading >= 0) {
+ Trace.endAsyncSection(sectionName, 0)
+ }
+ profile.appTargetLoading = time
+ Trace.beginAsyncSection(sectionName, 0)
+ }
+ }
+
+ fun endAppTargetLoadingSection(userHandle: UserHandle): Long {
+ val profile = getProfileRecord(userHandle, createIfMissing = false) ?: return -1L
+ val time = elapsedTimeNow()
+ val sectionName = userHandle.toAppTargetSectionName()
+ return synchronized(profile) {
+ if (profile.appTargetLoading >= 0) {
+ Trace.endAsyncSection(sectionName, 0)
+ (time - profile.appTargetLoading).also { profile.appTargetLoading = -1L }
+ } else {
+ -1L
+ }
+ }
+ }
+
+ private fun getUserShortcutRequestQueue(
+ userHandle: UserHandle,
+ createIfMissing: Boolean
+ ): ArrayDeque<LongArray>? = getProfileRecord(userHandle, createIfMissing)?.appPredictorRequests
+
+ private fun getProfileRecord(userHandle: UserHandle, createIfMissing: Boolean): ProfileRecord? =
+ synchronized(profileRecords) {
+ val idx = profileRecords.indexOfKey(userHandle.identifier)
+ when {
+ idx >= 0 -> profileRecords.valueAt(idx)
+ createIfMissing ->
+ ProfileRecord().also { profileRecords.put(userHandle.identifier, it) }
+ else -> null
+ }
+ }
+
private fun elapsedTimeNow() = SystemClock.elapsedRealtime()
}
+private class ProfileRecord {
+ val appPredictorRequests = ArrayDeque<LongArray>()
+ @GuardedBy("this") var appTargetLoading = -1L
+}
+
+private fun UserHandle.toAppPredictorSectionName() = SECTION_APP_PREDICTOR_PREFIX + identifier
+
+private fun UserHandle.toAppTargetSectionName() = SECTION_APP_TARGET_PREFIX + identifier
+
inline fun <R> runTracing(name: String, block: () -> R): R {
Trace.beginSection(name)
try {
diff --git a/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt b/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt
index ee6893d0..3ffbe039 100644
--- a/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt
+++ b/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt
@@ -38,6 +38,10 @@ import androidx.annotation.WorkerThread
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.coroutineScope
import com.android.intentresolver.chooser.DisplayResolveInfo
+import com.android.intentresolver.measurements.Tracer
+import com.android.intentresolver.measurements.runTracing
+import java.util.concurrent.Executor
+import java.util.function.Consumer
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
@@ -47,20 +51,19 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.launch
-import java.util.concurrent.Executor
-import java.util.function.Consumer
/**
* Encapsulates shortcuts loading logic from either AppPredictor or ShortcutManager.
*
- *
* A ShortcutLoader instance can be viewed as a per-profile singleton hot stream of shortcut
- * updates. The shortcut loading is triggered in the constructor or by the [reset] method,
- * the processing happens on the [dispatcher] and the result is delivered
- * through the [callback] on the default [lifecycle]'s dispatcher, the main thread.
+ * updates. The shortcut loading is triggered in the constructor or by the [reset] method, the
+ * processing happens on the [dispatcher] and the result is delivered through the [callback] on the
+ * default [lifecycle]'s dispatcher, the main thread.
*/
@OpenForTesting
-open class ShortcutLoader @VisibleForTesting constructor(
+open class ShortcutLoader
+@VisibleForTesting
+constructor(
private val context: Context,
private val lifecycle: Lifecycle,
private val appPredictor: AppPredictorProxy?,
@@ -73,13 +76,15 @@ open class ShortcutLoader @VisibleForTesting constructor(
private val shortcutToChooserTargetConverter = ShortcutToChooserTargetConverter()
private val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
private val appPredictorCallback = AppPredictor.Callback { onAppPredictorCallback(it) }
- private val appTargetSource = MutableSharedFlow<Array<DisplayResolveInfo>?>(
- replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST
- )
- private val shortcutSource = MutableSharedFlow<ShortcutData?>(
- replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST
- )
- private val isDestroyed get() = !lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)
+ private val appTargetSource =
+ MutableSharedFlow<Array<DisplayResolveInfo>?>(
+ replay = 1,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST
+ )
+ private val shortcutSource =
+ MutableSharedFlow<ShortcutData?>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
+ private val isDestroyed
+ get() = !lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)
@MainThread
constructor(
@@ -93,7 +98,8 @@ open class ShortcutLoader @VisibleForTesting constructor(
context,
lifecycle,
appPredictor?.let { AppPredictorProxy(it) },
- userHandle, userHandle == UserHandle.of(ActivityManager.getCurrentUser()),
+ userHandle,
+ userHandle == UserHandle.of(ActivityManager.getCurrentUser()),
targetIntentFilter,
Dispatchers.IO,
callback
@@ -103,43 +109,38 @@ open class ShortcutLoader @VisibleForTesting constructor(
appPredictor?.registerPredictionUpdates(dispatcher.asExecutor(), appPredictorCallback)
lifecycle.coroutineScope
.launch {
- appTargetSource.combine(shortcutSource) { appTargets, shortcutData ->
- if (appTargets == null || shortcutData == null) {
- null
- } else {
- filterShortcuts(
- appTargets,
- shortcutData.shortcuts,
- shortcutData.isFromAppPredictor,
- shortcutData.appPredictorTargets
- )
+ appTargetSource
+ .combine(shortcutSource) { appTargets, shortcutData ->
+ if (appTargets == null || shortcutData == null) {
+ null
+ } else {
+ runTracing("filter-shortcuts-${userHandle.identifier}") {
+ filterShortcuts(
+ appTargets,
+ shortcutData.shortcuts,
+ shortcutData.isFromAppPredictor,
+ shortcutData.appPredictorTargets
+ )
+ }
+ }
}
- }
- .filter { it != null }
- .flowOn(dispatcher)
- .collect {
- callback.accept(it ?: error("can not be null"))
- }
+ .filter { it != null }
+ .flowOn(dispatcher)
+ .collect { callback.accept(it ?: error("can not be null")) }
}
.invokeOnCompletion {
- runCatching {
- appPredictor?.unregisterPredictionUpdates(appPredictorCallback)
- }
+ runCatching { appPredictor?.unregisterPredictionUpdates(appPredictorCallback) }
Log.d(TAG, "destroyed, user: $userHandle")
}
reset()
}
- /**
- * Clear application targets (see [updateAppTargets] and initiate shrtcuts loading.
- */
+ /** Clear application targets (see [updateAppTargets] and initiate shrtcuts loading. */
fun reset() {
Log.d(TAG, "reset shortcut loader for user $userHandle")
appTargetSource.tryEmit(null)
shortcutSource.tryEmit(null)
- lifecycle.coroutineScope.launch(dispatcher) {
- loadShortcuts()
- }
+ lifecycle.coroutineScope.launch(dispatcher) { loadShortcuts() }
}
/**
@@ -154,7 +155,10 @@ open class ShortcutLoader @VisibleForTesting constructor(
@WorkerThread
private fun loadShortcuts() {
// no need to query direct share for work profile when its locked or disabled
- if (!shouldQueryDirectShareTargets()) return
+ if (!shouldQueryDirectShareTargets()) {
+ Log.d(TAG, "skip shortcuts loading for user $userHandle")
+ return
+ }
Log.d(TAG, "querying direct share targets for user $userHandle")
queryDirectShareTargets(false)
}
@@ -163,33 +167,49 @@ open class ShortcutLoader @VisibleForTesting constructor(
private fun queryDirectShareTargets(skipAppPredictionService: Boolean) {
if (!skipAppPredictionService && appPredictor != null) {
try {
+ Log.d(TAG, "query AppPredictor for user $userHandle")
+ Tracer.beginAppPredictorQueryTrace(userHandle)
appPredictor.requestPredictionUpdate()
return
} catch (e: Throwable) {
+ endAppPredictorQueryTrace(userHandle)
// we might have been destroyed concurrently, nothing left to do
- if (isDestroyed) return
+ if (isDestroyed) {
+ return
+ }
Log.e(TAG, "Failed to query AppPredictor for user $userHandle", e)
}
}
// Default to just querying ShortcutManager if AppPredictor not present.
- if (targetIntentFilter == null) return
- val shortcuts = queryShortcutManager(targetIntentFilter)
+ if (targetIntentFilter == null) {
+ Log.d(TAG, "skip querying ShortcutManager for $userHandle")
+ return
+ }
+ Log.d(TAG, "query ShortcutManager for user $userHandle")
+ val shortcuts =
+ runTracing("shortcut-mngr-${userHandle.identifier}") {
+ queryShortcutManager(targetIntentFilter)
+ }
+ Log.d(TAG, "receive shortcuts from ShortcutManager for user $userHandle")
sendShareShortcutInfoList(shortcuts, false, null)
}
@WorkerThread
private fun queryShortcutManager(targetIntentFilter: IntentFilter): List<ShareShortcutInfo> {
val selectedProfileContext = context.createContextAsUser(userHandle, 0 /* flags */)
- val sm = selectedProfileContext
- .getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager?
+ val sm =
+ selectedProfileContext.getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager?
val pm = context.createContextAsUser(userHandle, 0 /* flags */).packageManager
- return sm?.getShareTargets(targetIntentFilter)
- ?.filter { pm.isPackageEnabled(it.targetComponent.packageName) }
+ return sm?.getShareTargets(targetIntentFilter)?.filter {
+ pm.isPackageEnabled(it.targetComponent.packageName)
+ }
?: emptyList()
}
@WorkerThread
private fun onAppPredictorCallback(appPredictorTargets: List<AppTarget>) {
+ endAppPredictorQueryTrace(userHandle)
+ Log.d(TAG, "receive app targets from AppPredictor")
if (appPredictorTargets.isEmpty() && shouldQueryDirectShareTargets()) {
// APS may be disabled, so try querying targets ourselves.
queryDirectShareTargets(true)
@@ -202,9 +222,7 @@ open class ShortcutLoader @VisibleForTesting constructor(
@WorkerThread
private fun List<AppTarget>.toShortcuts(pm: PackageManager): ShortcutsAppTargetsPair =
- fold(
- ShortcutsAppTargetsPair(ArrayList(size), ArrayList(size))
- ) { acc, appTarget ->
+ fold(ShortcutsAppTargetsPair(ArrayList(size), ArrayList(size))) { acc, appTarget ->
val shortcutInfo = appTarget.shortcutInfo
val packageName = appTarget.packageName
val className = appTarget.className
@@ -234,9 +252,11 @@ open class ShortcutLoader @VisibleForTesting constructor(
): Result {
if (appPredictorTargets != null && appPredictorTargets.size != shortcuts.size) {
throw RuntimeException(
- "resultList and appTargets must have the same size."
- + " resultList.size()=" + shortcuts.size
- + " appTargets.size()=" + appPredictorTargets.size
+ "resultList and appTargets must have the same size." +
+ " resultList.size()=" +
+ shortcuts.size +
+ " appTargets.size()=" +
+ appPredictorTargets.size
)
}
val directShareAppTargetCache = HashMap<ChooserTarget, AppTarget>()
@@ -246,17 +266,17 @@ open class ShortcutLoader @VisibleForTesting constructor(
// ShareShortcutInfos directly.
val resultRecords: MutableList<ShortcutResultInfo> = ArrayList()
for (displayResolveInfo in appTargets) {
- val matchingShortcuts = shortcuts.filter {
- it.targetComponent == displayResolveInfo.resolvedComponentName
- }
+ val matchingShortcuts =
+ shortcuts.filter { it.targetComponent == displayResolveInfo.resolvedComponentName }
if (matchingShortcuts.isEmpty()) continue
- val chooserTargets = shortcutToChooserTargetConverter.convertToChooserTarget(
- matchingShortcuts,
- shortcuts,
- appPredictorTargets,
- directShareAppTargetCache,
- directShareShortcutInfoCache
- )
+ val chooserTargets =
+ shortcutToChooserTargetConverter.convertToChooserTarget(
+ matchingShortcuts,
+ shortcuts,
+ appPredictorTargets,
+ directShareAppTargetCache,
+ directShareShortcutInfoCache
+ )
val resultRecord = ShortcutResultInfo(displayResolveInfo, chooserTargets)
resultRecords.add(resultRecord)
}
@@ -270,16 +290,17 @@ open class ShortcutLoader @VisibleForTesting constructor(
}
/**
- * Returns `false` if `userHandle` is the work profile and it's either
- * in quiet mode or not running.
+ * Returns `false` if `userHandle` is the work profile and it's either in quiet mode or not
+ * running.
*/
private fun shouldQueryDirectShareTargets(): Boolean = isPersonalProfile || isProfileActive
@get:VisibleForTesting
protected val isProfileActive: Boolean
- get() = userManager.isUserRunning(userHandle)
- && userManager.isUserUnlocked(userHandle)
- && !userManager.isQuietModeEnabled(userHandle)
+ get() =
+ userManager.isUserRunning(userHandle) &&
+ userManager.isUserUnlocked(userHandle) &&
+ !userManager.isQuietModeEnabled(userHandle)
private class ShortcutData(
val shortcuts: List<ShareShortcutInfo>,
@@ -287,27 +308,21 @@ open class ShortcutLoader @VisibleForTesting constructor(
val appPredictorTargets: List<AppTarget>?
)
- /**
- * Resolved shortcuts with corresponding app targets.
- */
+ /** Resolved shortcuts with corresponding app targets. */
class Result(
val isFromAppPredictor: Boolean,
/**
- * Input app targets (see [ShortcutLoader.updateAppTargets] the
- * shortcuts were process against.
+ * Input app targets (see [ShortcutLoader.updateAppTargets] the shortcuts were process
+ * against.
*/
val appTargets: Array<DisplayResolveInfo>,
- /**
- * Shortcuts grouped by app target.
- */
+ /** Shortcuts grouped by app target. */
val shortcutsByApp: Array<ShortcutResultInfo>,
val directShareAppTargetCache: Map<ChooserTarget, AppTarget>,
val directShareShortcutInfoCache: Map<ChooserTarget, ShortcutInfo>
)
- /**
- * Shortcuts grouped by app.
- */
+ /** Shortcuts grouped by app. */
class ShortcutResultInfo(
val appTarget: DisplayResolveInfo,
val shortcuts: List<ChooserTarget?>
@@ -318,27 +333,20 @@ open class ShortcutLoader @VisibleForTesting constructor(
val appTargets: List<AppTarget>?
)
- /**
- * A wrapper around AppPredictor to facilitate unit-testing.
- */
+ /** A wrapper around AppPredictor to facilitate unit-testing. */
@VisibleForTesting
open class AppPredictorProxy internal constructor(private val mAppPredictor: AppPredictor) {
- /**
- * [AppPredictor.registerPredictionUpdates]
- */
+ /** [AppPredictor.registerPredictionUpdates] */
open fun registerPredictionUpdates(
- callbackExecutor: Executor, callback: AppPredictor.Callback
+ callbackExecutor: Executor,
+ callback: AppPredictor.Callback
) = mAppPredictor.registerPredictionUpdates(callbackExecutor, callback)
- /**
- * [AppPredictor.unregisterPredictionUpdates]
- */
+ /** [AppPredictor.unregisterPredictionUpdates] */
open fun unregisterPredictionUpdates(callback: AppPredictor.Callback) =
mAppPredictor.unregisterPredictionUpdates(callback)
- /**
- * [AppPredictor.requestPredictionUpdate]
- */
+ /** [AppPredictor.requestPredictionUpdate] */
open fun requestPredictionUpdate() = mAppPredictor.requestPredictionUpdate()
}
@@ -350,12 +358,21 @@ open class ShortcutLoader @VisibleForTesting constructor(
return false
}
return runCatching {
- val appInfo = getApplicationInfo(
- packageName,
- PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong())
- )
- appInfo.enabled && (appInfo.flags and ApplicationInfo.FLAG_SUSPENDED) == 0
- }.getOrDefault(false)
+ val appInfo =
+ getApplicationInfo(
+ packageName,
+ PackageManager.ApplicationInfoFlags.of(
+ PackageManager.GET_META_DATA.toLong()
+ )
+ )
+ appInfo.enabled && (appInfo.flags and ApplicationInfo.FLAG_SUSPENDED) == 0
+ }
+ .getOrDefault(false)
+ }
+
+ private fun endAppPredictorQueryTrace(userHandle: UserHandle) {
+ val duration = Tracer.endAppPredictorQueryTrace(userHandle)
+ Log.d(TAG, "AppPredictor query duration for user $userHandle: $duration ms")
}
}
}