diff options
author | Pierfrancesco Soffritti <psoffritti@google.com> | 2022-02-23 16:39:45 +0000 |
---|---|---|
committer | Pierfrancesco Soffritti <psoffritti@google.com> | 2022-03-08 15:09:35 +0000 |
commit | f1ec2d9c6ee7a37fd71213490116081c9e353f19 (patch) | |
tree | 72ff649535f4821c9a134a6f3639dea8eae7bb3d /layout-inspector/src | |
parent | 27891d95e92ff4944891a65fcba8a1e235a61c33 (diff) | |
download | idea-f1ec2d9c6ee7a37fd71213490116081c9e353f19.tar.gz |
Update spinner message during connection
When connecting to AppInspectionInspectorClient we have a
30 seconds timeout. When the timeout is reached we fallback
to the LegacyClient.
This change updates the UI so that the user is updated
every time we make progress in the connection process.
By doing this the user will know that something is happening.
Test: InspectorClientLaunchMonitorTest, InspectorModelTest
Bug: 209700484
Change-Id: I1d2b804df06f7bd63d8e25556bdc3d24a6ad993d
Diffstat (limited to 'layout-inspector/src')
6 files changed, 63 insertions, 3 deletions
diff --git a/layout-inspector/src/com/android/tools/idea/layoutinspector/LayoutInspector.kt b/layout-inspector/src/com/android/tools/idea/layoutinspector/LayoutInspector.kt index c169e3f49f3..95088661707 100644 --- a/layout-inspector/src/com/android/tools/idea/layoutinspector/LayoutInspector.kt +++ b/layout-inspector/src/com/android/tools/idea/layoutinspector/LayoutInspector.kt @@ -92,6 +92,7 @@ class LayoutInspector private constructor( client.registerErrorCallback(::logError) client.registerTreeEventCallback(::loadComponentTree) client.registerStateCallback { state -> if (state == InspectorClient.State.CONNECTED) updateConnection(client) } + client.registerConnectionTimeoutCallback { state -> layoutInspectorModel.fireAttachStateEvent(state) } stats.start(client.isCapturing) } else { diff --git a/layout-inspector/src/com/android/tools/idea/layoutinspector/model/InspectorModel.kt b/layout-inspector/src/com/android/tools/idea/layoutinspector/model/InspectorModel.kt index b57938c36a6..22df6436bca 100644 --- a/layout-inspector/src/com/android/tools/idea/layoutinspector/model/InspectorModel.kt +++ b/layout-inspector/src/com/android/tools/idea/layoutinspector/model/InspectorModel.kt @@ -20,6 +20,7 @@ import com.android.tools.idea.layoutinspector.pipeline.InspectorClient import com.android.tools.idea.layoutinspector.properties.ViewNodeAndResourceLookup import com.android.tools.idea.layoutinspector.resource.ResourceLookup import com.android.tools.idea.util.ListenerCollection +import com.google.wireless.android.sdk.stats.DynamicLayoutInspectorErrorInfo import com.intellij.openapi.project.Project import layoutinspector.view.inspection.LayoutInspectorViewProtocol import layoutinspector.view.inspection.LayoutInspectorViewProtocol.FoldEvent.SpecialAngles.NO_FOLD_ANGLE_VALUE @@ -66,6 +67,9 @@ class InspectorModel(val project: Project) : ViewNodeAndResourceLookup { } } + // TODO: update all listeners to use ListenerCollection + val attachStageListeners = ListenerCollection.createWithDirectExecutor<(DynamicLayoutInspectorErrorInfo.AttachErrorState) -> Unit>() + val windows = mutableMapOf<Any, AndroidWindow>() // synthetic node to hold the roots of the current windows. val root = ViewNode("android.root - hide") @@ -132,6 +136,10 @@ class InspectorModel(val project: Project) : ViewNodeAndResourceLookup { */ operator fun get(id: String) = ViewNode.readAccess { root.flatten().find { it.viewId?.name == id } } + fun fireAttachStateEvent(state: DynamicLayoutInspectorErrorInfo.AttachErrorState) { + attachStageListeners.forEach { it.invoke(state) } + } + /** * Get the root of the view tree that the [view] parameter lives in. * diff --git a/layout-inspector/src/com/android/tools/idea/layoutinspector/pipeline/AbstractInspectorClient.kt b/layout-inspector/src/com/android/tools/idea/layoutinspector/pipeline/AbstractInspectorClient.kt index b3740644305..a8c50e083e5 100644 --- a/layout-inspector/src/com/android/tools/idea/layoutinspector/pipeline/AbstractInspectorClient.kt +++ b/layout-inspector/src/com/android/tools/idea/layoutinspector/pipeline/AbstractInspectorClient.kt @@ -54,8 +54,9 @@ abstract class AbstractInspectorClient( private val stateCallbacks = ListenerCollection.createWithDirectExecutor<(InspectorClient.State) -> Unit>() private val errorCallbacks = ListenerCollection.createWithDirectExecutor<(String) -> Unit>() private val treeEventCallbacks = ListenerCollection.createWithDirectExecutor<(Any) -> Unit>() + private val attachStateListeners = ListenerCollection.createWithDirectExecutor<(DynamicLayoutInspectorErrorInfo.AttachErrorState) -> Unit>() - var launchMonitor: InspectorClientLaunchMonitor = InspectorClientLaunchMonitor() + var launchMonitor: InspectorClientLaunchMonitor = InspectorClientLaunchMonitor(attachStateListeners) @TestOnly set override fun dispose() { @@ -74,6 +75,10 @@ abstract class AbstractInspectorClient( treeEventCallbacks.add(callback) } + final override fun registerConnectionTimeoutCallback(callback: (DynamicLayoutInspectorErrorInfo.AttachErrorState) -> Unit) { + attachStateListeners.add(callback) + } + /** * Fire relevant callbacks registered with [registerStateCallback], if present. */ diff --git a/layout-inspector/src/com/android/tools/idea/layoutinspector/pipeline/InspectorClient.kt b/layout-inspector/src/com/android/tools/idea/layoutinspector/pipeline/InspectorClient.kt index 7fd8df33d85..18a5fad2266 100644 --- a/layout-inspector/src/com/android/tools/idea/layoutinspector/pipeline/InspectorClient.kt +++ b/layout-inspector/src/com/android/tools/idea/layoutinspector/pipeline/InspectorClient.kt @@ -94,6 +94,11 @@ interface InspectorClient: Disposable { fun registerTreeEventCallback(callback: (Any) -> Unit) /** + * Register a handle that is triggered when this client receives a launch event. + */ + fun registerConnectionTimeoutCallback(callback: (DynamicLayoutInspectorErrorInfo.AttachErrorState) -> Unit) + + /** * Connect this client to the device. * * Use [registerStateCallback] and check for [State.CONNECTED] if you need to know when this has @@ -214,6 +219,8 @@ object DisconnectedClient : InspectorClient { override fun registerStateCallback(callback: (InspectorClient.State) -> Unit) = Unit override fun registerErrorCallback(callback: (String) -> Unit) = Unit override fun registerTreeEventCallback(callback: (Any) -> Unit) = Unit + override fun registerConnectionTimeoutCallback(callback: (DynamicLayoutInspectorErrorInfo.AttachErrorState) -> Unit) = Unit + override fun startFetching(): CompletableFuture<Unit> = CompletableFuture.completedFuture(Unit) override fun stopFetching(): CompletableFuture<Unit> = CompletableFuture.completedFuture(Unit) override fun refresh() {} diff --git a/layout-inspector/src/com/android/tools/idea/layoutinspector/pipeline/InspectorClientLaunchMonitor.kt b/layout-inspector/src/com/android/tools/idea/layoutinspector/pipeline/InspectorClientLaunchMonitor.kt index adcc24f7f7f..da130174865 100644 --- a/layout-inspector/src/com/android/tools/idea/layoutinspector/pipeline/InspectorClientLaunchMonitor.kt +++ b/layout-inspector/src/com/android/tools/idea/layoutinspector/pipeline/InspectorClientLaunchMonitor.kt @@ -16,6 +16,7 @@ package com.android.tools.idea.layoutinspector.pipeline import com.android.tools.idea.layoutinspector.metrics.LayoutInspectorMetrics +import com.android.tools.idea.util.ListenerCollection import com.google.wireless.android.sdk.stats.DynamicLayoutInspectorErrorInfo.AttachErrorState import com.google.wireless.android.sdk.stats.DynamicLayoutInspectorEvent import com.intellij.openapi.diagnostic.Logger @@ -30,6 +31,7 @@ import java.util.concurrent.TimeUnit @VisibleForTesting const val CONNECT_TIMEOUT_SECONDS: Long = 30L class InspectorClientLaunchMonitor( + private val attachErrorStateListeners: ListenerCollection<(AttachErrorState) -> Unit>, @TestOnly private val executorService: ScheduledExecutorService = AppExecutorUtil.getAppScheduledExecutorService() ) { private var lastUpdate: Long = 0L @@ -44,6 +46,8 @@ class InspectorClientLaunchMonitor( } fun updateProgress(progress: AttachErrorState) { + attachErrorStateListeners.forEach { it.invoke(progress) } + if (progress <= currentProgress) { return } diff --git a/layout-inspector/src/com/android/tools/idea/layoutinspector/ui/DeviceViewPanel.kt b/layout-inspector/src/com/android/tools/idea/layoutinspector/ui/DeviceViewPanel.kt index 3b206579304..040cd7e8e2a 100644 --- a/layout-inspector/src/com/android/tools/idea/layoutinspector/ui/DeviceViewPanel.kt +++ b/layout-inspector/src/com/android/tools/idea/layoutinspector/ui/DeviceViewPanel.kt @@ -33,7 +33,6 @@ import com.android.tools.idea.appinspection.ide.ui.SelectProcessAction import com.android.tools.idea.appinspection.ide.ui.buildDeviceName import com.android.tools.idea.appinspection.inspector.api.process.DeviceDescriptor import com.android.tools.idea.concurrency.AndroidExecutors -import com.android.tools.idea.flags.StudioFlags import com.android.tools.idea.layoutinspector.LayoutInspector import com.android.tools.idea.layoutinspector.model.REBOOT_FOR_LIVE_INSPECTOR_MESSAGE_KEY import com.android.tools.idea.layoutinspector.model.ViewNode @@ -43,6 +42,7 @@ import com.android.tools.idea.layoutinspector.pipeline.InspectorClient.Capabilit import com.android.tools.idea.layoutinspector.pipeline.InspectorClientSettings import com.android.tools.idea.layoutinspector.snapshots.CaptureSnapshotAction import com.google.common.annotations.VisibleForTesting +import com.google.wireless.android.sdk.stats.DynamicLayoutInspectorErrorInfo import com.intellij.icons.AllIcons import com.intellij.ide.BrowserUtil import com.intellij.openapi.Disposable @@ -67,6 +67,7 @@ import icons.StudioIcons import icons.StudioIcons.LayoutInspector.LIVE_UPDATES import org.jetbrains.android.util.AndroidBundle import org.jetbrains.annotations.TestOnly +import org.jetbrains.kotlin.idea.actions.internal.refactoringTesting.edtExecute import java.awt.BorderLayout import java.awt.Container import java.awt.Cursor @@ -304,6 +305,40 @@ class DeviceViewPanel( loadingPane.add(layeredPane, BorderLayout.CENTER) add(loadingPane, BorderLayout.CENTER) val model = layoutInspector.layoutInspectorModel + + model.attachStageListeners.add { state -> + val text = when (state) { + DynamicLayoutInspectorErrorInfo.AttachErrorState.UNKNOWN_ATTACH_ERROR_STATE -> "Unknown state" + DynamicLayoutInspectorErrorInfo.AttachErrorState.NOT_STARTED -> "Starting" + DynamicLayoutInspectorErrorInfo.AttachErrorState.ADB_PING -> "Adb ping success" + DynamicLayoutInspectorErrorInfo.AttachErrorState.ATTACH_SUCCESS -> "Attach success" + DynamicLayoutInspectorErrorInfo.AttachErrorState.START_REQUEST_SENT -> "Start request sent" + DynamicLayoutInspectorErrorInfo.AttachErrorState.START_RECEIVED -> "Start request received" + DynamicLayoutInspectorErrorInfo.AttachErrorState.STARTED -> "Started" + DynamicLayoutInspectorErrorInfo.AttachErrorState.ROOTS_EVENT_SENT -> "Roots sent" + DynamicLayoutInspectorErrorInfo.AttachErrorState.ROOTS_EVENT_RECEIVED -> "Roots received" + DynamicLayoutInspectorErrorInfo.AttachErrorState.VIEW_INVALIDATION_CALLBACK -> "Capture started" + DynamicLayoutInspectorErrorInfo.AttachErrorState.SCREENSHOT_CAPTURED -> "Screenshot captured" + DynamicLayoutInspectorErrorInfo.AttachErrorState.VIEW_HIERARCHY_CAPTURED -> "Hierarchy captured" + DynamicLayoutInspectorErrorInfo.AttachErrorState.RESPONSE_SENT -> "Response sent" + DynamicLayoutInspectorErrorInfo.AttachErrorState.LAYOUT_EVENT_RECEIVED -> "View information received" + DynamicLayoutInspectorErrorInfo.AttachErrorState.COMPOSE_REQUEST_SENT -> "Compose information request" + DynamicLayoutInspectorErrorInfo.AttachErrorState.COMPOSE_RESPONSE_RECEIVED -> "Compose information received" + DynamicLayoutInspectorErrorInfo.AttachErrorState.LEGACY_WINDOW_LIST_REQUESTED -> "Legacy window list requested" + DynamicLayoutInspectorErrorInfo.AttachErrorState.LEGACY_WINDOW_LIST_RECEIVED -> "Legacy window list received" + DynamicLayoutInspectorErrorInfo.AttachErrorState.LEGACY_HIERARCHY_REQUESTED -> "Legacy hierarchy requested" + DynamicLayoutInspectorErrorInfo.AttachErrorState.LEGACY_HIERARCHY_RECEIVED -> "Legacy hierarchy received" + DynamicLayoutInspectorErrorInfo.AttachErrorState.LEGACY_SCREENSHOT_REQUESTED -> "Legacy screenshot requested" + DynamicLayoutInspectorErrorInfo.AttachErrorState.LEGACY_SCREENSHOT_RECEIVED -> "Legacy screenshot received" + DynamicLayoutInspectorErrorInfo.AttachErrorState.PARSED_COMPONENT_TREE -> "Compose tree parsed" + DynamicLayoutInspectorErrorInfo.AttachErrorState.MODEL_UPDATED -> "Update complete" + } + + if (text.isNotEmpty()) { + loadingPane.setLoadingText(text) + } + } + processes?.addSelectedProcessListeners(newSingleThreadExecutor()) { if (processes.selectedProcess?.isRunning == true) { if (model.isEmpty) { @@ -311,7 +346,7 @@ class DeviceViewPanel( } } if (processes.selectedProcess == null) { - loadingPane.stopLoading() + loadingPane.stopLoading() } } model.modificationListeners.add { old, new, _ -> |