[go: nahoru, domu]

Make EditorSession timeout if there's an error and make EditorSession.createOnWatchEditingSession NonNull

For incorrect ComponentName don't send null session, but instead
wait for a timeout and throw exception. Consequently,
EditorSession.createOnWatchEditingSession and EditorRequest.createFromIntent
won't return null.

Bug: 182792664
Test: Added EditingSessionTest.createOnWatchEditingSessionThrowsTimeoutException
Relnote: "We have made EditorSession.createOnWatchEditingSession throw TimeoutCancellationException if there's an error instead of sending null session. Additionally, return value of EditorRequest.createFromIntent and EditorSession.createOnWatchEditingSession is now NonNull."
Change-Id: I41eb47cbe25cdc5e945752f20cba0a56f3bbce05
diff --git a/wear/wear-watchface-editor/api/current.txt b/wear/wear-watchface-editor/api/current.txt
index f1dddbb..193bdea 100644
--- a/wear/wear-watchface-editor/api/current.txt
+++ b/wear/wear-watchface-editor/api/current.txt
@@ -14,7 +14,7 @@
   public final class EditorRequest {
     ctor @RequiresApi(android.os.Build.VERSION_CODES.R) public EditorRequest(android.content.ComponentName watchFaceComponentName, String editorPackageName, androidx.wear.watchface.style.UserStyleData? initialUserStyle, @RequiresApi(android.os.Build.VERSION_CODES.R) androidx.wear.watchface.client.WatchFaceId watchFaceId);
     ctor public EditorRequest(android.content.ComponentName watchFaceComponentName, String editorPackageName, androidx.wear.watchface.style.UserStyleData? initialUserStyle);
-    method public static androidx.wear.watchface.editor.EditorRequest? createFromIntent(android.content.Intent intent);
+    method @kotlin.jvm.Throws(exceptionClasses=TimeoutCancellationException::class) public static androidx.wear.watchface.editor.EditorRequest createFromIntent(android.content.Intent intent) throws kotlinx.coroutines.TimeoutCancellationException;
     method public String getEditorPackageName();
     method public androidx.wear.watchface.style.UserStyleData? getInitialUserStyle();
     method public android.content.ComponentName getWatchFaceComponentName();
@@ -27,13 +27,13 @@
   }
 
   public static final class EditorRequest.Companion {
-    method public androidx.wear.watchface.editor.EditorRequest? createFromIntent(android.content.Intent intent);
+    method @kotlin.jvm.Throws(exceptionClasses=TimeoutCancellationException::class) public androidx.wear.watchface.editor.EditorRequest createFromIntent(android.content.Intent intent) throws kotlinx.coroutines.TimeoutCancellationException;
   }
 
   public abstract class EditorSession implements java.lang.AutoCloseable {
     ctor public EditorSession();
-    method @RequiresApi(27) @UiThread public static final androidx.wear.watchface.editor.EditorSession? createHeadlessEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, androidx.wear.watchface.client.HeadlessWatchFaceClient headlessWatchFaceClient);
-    method @UiThread public static final suspend Object? createOnWatchEditingSession(androidx.activity.ComponentActivity p, android.content.Intent activity, kotlin.coroutines.Continuation<? super androidx.wear.watchface.editor.EditorSession> editIntent);
+    method @RequiresApi(27) @UiThread public static final androidx.wear.watchface.editor.EditorSession createHeadlessEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, androidx.wear.watchface.client.HeadlessWatchFaceClient headlessWatchFaceClient);
+    method @UiThread @kotlin.jvm.Throws(exceptionClasses=TimeoutCancellationException::class) public static final suspend Object? createOnWatchEditingSession(androidx.activity.ComponentActivity p, android.content.Intent activity, kotlin.coroutines.Continuation<? super androidx.wear.watchface.editor.EditorSession> editIntent) throws kotlinx.coroutines.TimeoutCancellationException;
     method public abstract Integer? getBackgroundComplicationId();
     method @UiThread public abstract Integer? getComplicationIdAt(@Px int x, @Px int y);
     method @UiThread public abstract suspend Object? getComplicationsPreviewData(kotlin.coroutines.Continuation<? super java.util.Map<java.lang.Integer,? extends androidx.wear.complications.data.ComplicationData>> p);
@@ -57,11 +57,12 @@
     property public abstract android.content.ComponentName watchFaceComponentName;
     property @RequiresApi(android.os.Build.VERSION_CODES.R) public abstract androidx.wear.watchface.client.WatchFaceId watchFaceId;
     field public static final androidx.wear.watchface.editor.EditorSession.Companion Companion;
+    field public static final long EDITING_SESSION_TIMEOUT_MILLIS = 4000L; // 0xfa0L
   }
 
   public static final class EditorSession.Companion {
-    method @RequiresApi(27) @UiThread public androidx.wear.watchface.editor.EditorSession? createHeadlessEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, androidx.wear.watchface.client.HeadlessWatchFaceClient headlessWatchFaceClient);
-    method @UiThread public suspend Object? createOnWatchEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, kotlin.coroutines.Continuation<? super androidx.wear.watchface.editor.EditorSession> p);
+    method @RequiresApi(27) @UiThread public androidx.wear.watchface.editor.EditorSession createHeadlessEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, androidx.wear.watchface.client.HeadlessWatchFaceClient headlessWatchFaceClient);
+    method @UiThread @kotlin.jvm.Throws(exceptionClasses=TimeoutCancellationException::class) public suspend Object? createOnWatchEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, kotlin.coroutines.Continuation<? super androidx.wear.watchface.editor.EditorSession> p) throws kotlinx.coroutines.TimeoutCancellationException;
   }
 
   public final class EditorSessionKt {
diff --git a/wear/wear-watchface-editor/api/public_plus_experimental_current.txt b/wear/wear-watchface-editor/api/public_plus_experimental_current.txt
index f1dddbb..193bdea 100644
--- a/wear/wear-watchface-editor/api/public_plus_experimental_current.txt
+++ b/wear/wear-watchface-editor/api/public_plus_experimental_current.txt
@@ -14,7 +14,7 @@
   public final class EditorRequest {
     ctor @RequiresApi(android.os.Build.VERSION_CODES.R) public EditorRequest(android.content.ComponentName watchFaceComponentName, String editorPackageName, androidx.wear.watchface.style.UserStyleData? initialUserStyle, @RequiresApi(android.os.Build.VERSION_CODES.R) androidx.wear.watchface.client.WatchFaceId watchFaceId);
     ctor public EditorRequest(android.content.ComponentName watchFaceComponentName, String editorPackageName, androidx.wear.watchface.style.UserStyleData? initialUserStyle);
-    method public static androidx.wear.watchface.editor.EditorRequest? createFromIntent(android.content.Intent intent);
+    method @kotlin.jvm.Throws(exceptionClasses=TimeoutCancellationException::class) public static androidx.wear.watchface.editor.EditorRequest createFromIntent(android.content.Intent intent) throws kotlinx.coroutines.TimeoutCancellationException;
     method public String getEditorPackageName();
     method public androidx.wear.watchface.style.UserStyleData? getInitialUserStyle();
     method public android.content.ComponentName getWatchFaceComponentName();
@@ -27,13 +27,13 @@
   }
 
   public static final class EditorRequest.Companion {
-    method public androidx.wear.watchface.editor.EditorRequest? createFromIntent(android.content.Intent intent);
+    method @kotlin.jvm.Throws(exceptionClasses=TimeoutCancellationException::class) public androidx.wear.watchface.editor.EditorRequest createFromIntent(android.content.Intent intent) throws kotlinx.coroutines.TimeoutCancellationException;
   }
 
   public abstract class EditorSession implements java.lang.AutoCloseable {
     ctor public EditorSession();
-    method @RequiresApi(27) @UiThread public static final androidx.wear.watchface.editor.EditorSession? createHeadlessEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, androidx.wear.watchface.client.HeadlessWatchFaceClient headlessWatchFaceClient);
-    method @UiThread public static final suspend Object? createOnWatchEditingSession(androidx.activity.ComponentActivity p, android.content.Intent activity, kotlin.coroutines.Continuation<? super androidx.wear.watchface.editor.EditorSession> editIntent);
+    method @RequiresApi(27) @UiThread public static final androidx.wear.watchface.editor.EditorSession createHeadlessEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, androidx.wear.watchface.client.HeadlessWatchFaceClient headlessWatchFaceClient);
+    method @UiThread @kotlin.jvm.Throws(exceptionClasses=TimeoutCancellationException::class) public static final suspend Object? createOnWatchEditingSession(androidx.activity.ComponentActivity p, android.content.Intent activity, kotlin.coroutines.Continuation<? super androidx.wear.watchface.editor.EditorSession> editIntent) throws kotlinx.coroutines.TimeoutCancellationException;
     method public abstract Integer? getBackgroundComplicationId();
     method @UiThread public abstract Integer? getComplicationIdAt(@Px int x, @Px int y);
     method @UiThread public abstract suspend Object? getComplicationsPreviewData(kotlin.coroutines.Continuation<? super java.util.Map<java.lang.Integer,? extends androidx.wear.complications.data.ComplicationData>> p);
@@ -57,11 +57,12 @@
     property public abstract android.content.ComponentName watchFaceComponentName;
     property @RequiresApi(android.os.Build.VERSION_CODES.R) public abstract androidx.wear.watchface.client.WatchFaceId watchFaceId;
     field public static final androidx.wear.watchface.editor.EditorSession.Companion Companion;
+    field public static final long EDITING_SESSION_TIMEOUT_MILLIS = 4000L; // 0xfa0L
   }
 
   public static final class EditorSession.Companion {
-    method @RequiresApi(27) @UiThread public androidx.wear.watchface.editor.EditorSession? createHeadlessEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, androidx.wear.watchface.client.HeadlessWatchFaceClient headlessWatchFaceClient);
-    method @UiThread public suspend Object? createOnWatchEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, kotlin.coroutines.Continuation<? super androidx.wear.watchface.editor.EditorSession> p);
+    method @RequiresApi(27) @UiThread public androidx.wear.watchface.editor.EditorSession createHeadlessEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, androidx.wear.watchface.client.HeadlessWatchFaceClient headlessWatchFaceClient);
+    method @UiThread @kotlin.jvm.Throws(exceptionClasses=TimeoutCancellationException::class) public suspend Object? createOnWatchEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, kotlin.coroutines.Continuation<? super androidx.wear.watchface.editor.EditorSession> p) throws kotlinx.coroutines.TimeoutCancellationException;
   }
 
   public final class EditorSessionKt {
diff --git a/wear/wear-watchface-editor/api/restricted_current.txt b/wear/wear-watchface-editor/api/restricted_current.txt
index 5ab6ecc..fedbc34 100644
--- a/wear/wear-watchface-editor/api/restricted_current.txt
+++ b/wear/wear-watchface-editor/api/restricted_current.txt
@@ -34,7 +34,7 @@
   public final class EditorRequest {
     ctor @RequiresApi(android.os.Build.VERSION_CODES.R) public EditorRequest(android.content.ComponentName watchFaceComponentName, String editorPackageName, androidx.wear.watchface.style.UserStyleData? initialUserStyle, @RequiresApi(android.os.Build.VERSION_CODES.R) androidx.wear.watchface.client.WatchFaceId watchFaceId);
     ctor public EditorRequest(android.content.ComponentName watchFaceComponentName, String editorPackageName, androidx.wear.watchface.style.UserStyleData? initialUserStyle);
-    method public static androidx.wear.watchface.editor.EditorRequest? createFromIntent(android.content.Intent intent);
+    method @kotlin.jvm.Throws(exceptionClasses=TimeoutCancellationException::class) public static androidx.wear.watchface.editor.EditorRequest createFromIntent(android.content.Intent intent) throws kotlinx.coroutines.TimeoutCancellationException;
     method public String getEditorPackageName();
     method public androidx.wear.watchface.style.UserStyleData? getInitialUserStyle();
     method public android.content.ComponentName getWatchFaceComponentName();
@@ -47,13 +47,13 @@
   }
 
   public static final class EditorRequest.Companion {
-    method public androidx.wear.watchface.editor.EditorRequest? createFromIntent(android.content.Intent intent);
+    method @kotlin.jvm.Throws(exceptionClasses=TimeoutCancellationException::class) public androidx.wear.watchface.editor.EditorRequest createFromIntent(android.content.Intent intent) throws kotlinx.coroutines.TimeoutCancellationException;
   }
 
   public abstract class EditorSession implements java.lang.AutoCloseable {
     ctor public EditorSession();
-    method @RequiresApi(27) @UiThread public static final androidx.wear.watchface.editor.EditorSession? createHeadlessEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, androidx.wear.watchface.client.HeadlessWatchFaceClient headlessWatchFaceClient);
-    method @UiThread public static final suspend Object? createOnWatchEditingSession(androidx.activity.ComponentActivity p, android.content.Intent activity, kotlin.coroutines.Continuation<? super androidx.wear.watchface.editor.EditorSession> editIntent);
+    method @RequiresApi(27) @UiThread public static final androidx.wear.watchface.editor.EditorSession createHeadlessEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, androidx.wear.watchface.client.HeadlessWatchFaceClient headlessWatchFaceClient);
+    method @UiThread @kotlin.jvm.Throws(exceptionClasses=TimeoutCancellationException::class) public static final suspend Object? createOnWatchEditingSession(androidx.activity.ComponentActivity p, android.content.Intent activity, kotlin.coroutines.Continuation<? super androidx.wear.watchface.editor.EditorSession> editIntent) throws kotlinx.coroutines.TimeoutCancellationException;
     method public abstract Integer? getBackgroundComplicationId();
     method @UiThread public abstract Integer? getComplicationIdAt(@Px int x, @Px int y);
     method @UiThread public abstract suspend Object? getComplicationsPreviewData(kotlin.coroutines.Continuation<? super java.util.Map<java.lang.Integer,? extends androidx.wear.complications.data.ComplicationData>> p);
@@ -77,11 +77,12 @@
     property public abstract android.content.ComponentName watchFaceComponentName;
     property @RequiresApi(android.os.Build.VERSION_CODES.R) public abstract androidx.wear.watchface.client.WatchFaceId watchFaceId;
     field public static final androidx.wear.watchface.editor.EditorSession.Companion Companion;
+    field public static final long EDITING_SESSION_TIMEOUT_MILLIS = 4000L; // 0xfa0L
   }
 
   public static final class EditorSession.Companion {
-    method @RequiresApi(27) @UiThread public androidx.wear.watchface.editor.EditorSession? createHeadlessEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, androidx.wear.watchface.client.HeadlessWatchFaceClient headlessWatchFaceClient);
-    method @UiThread public suspend Object? createOnWatchEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, kotlin.coroutines.Continuation<? super androidx.wear.watchface.editor.EditorSession> p);
+    method @RequiresApi(27) @UiThread public androidx.wear.watchface.editor.EditorSession createHeadlessEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, androidx.wear.watchface.client.HeadlessWatchFaceClient headlessWatchFaceClient);
+    method @UiThread @kotlin.jvm.Throws(exceptionClasses=TimeoutCancellationException::class) public suspend Object? createOnWatchEditingSession(androidx.activity.ComponentActivity activity, android.content.Intent editIntent, kotlin.coroutines.Continuation<? super androidx.wear.watchface.editor.EditorSession> p) throws kotlinx.coroutines.TimeoutCancellationException;
   }
 
   public final class EditorSessionKt {
diff --git a/wear/wear-watchface-editor/guava/src/main/java/androidx/wear/watchface/editor/ListenableEditorSession.kt b/wear/wear-watchface-editor/guava/src/main/java/androidx/wear/watchface/editor/ListenableEditorSession.kt
index f6c92d1..4b36de1 100644
--- a/wear/wear-watchface-editor/guava/src/main/java/androidx/wear/watchface/editor/ListenableEditorSession.kt
+++ b/wear/wear-watchface-editor/guava/src/main/java/androidx/wear/watchface/editor/ListenableEditorSession.kt
@@ -34,6 +34,7 @@
 import com.google.common.util.concurrent.ListenableFuture
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.TimeoutCancellationException
 import kotlinx.coroutines.launch
 import kotlin.coroutines.CoroutineContext
 
@@ -48,6 +49,9 @@
          * Constructs a [ListenableFuture] for a [ListenableEditorSession] for an on watch face
          * editor. This registers an activity result handler and so it must be called during an
          * Activity or Fragment initialization path.
+         *
+         * If watch face editor takes more than 4s to create a watch face, returned future will be
+         * resolved with [TimeoutCancellationException] exception.
          */
         @SuppressWarnings("ExecutorRegistration")
         @JvmStatic
@@ -69,9 +73,7 @@
             coroutineScope.launch {
                 try {
                     result.set(
-                        createOnWatchEditingSession(activity, editIntent)?.let {
-                            ListenableEditorSession(it)
-                        }
+                        ListenableEditorSession(createOnWatchEditingSession(activity, editIntent))
                     )
                 } catch (e: Exception) {
                     result.setException(e)
@@ -96,7 +98,7 @@
             activity,
             editIntent,
             headlessWatchFaceClient
-        )?.let {
+        ).let {
             ListenableEditorSession(it)
         }
     }
diff --git a/wear/wear-watchface-editor/samples/src/main/java/androidx/wear/watchface/editor/sample/WatchFaceConfigActivity.kt b/wear/wear-watchface-editor/samples/src/main/java/androidx/wear/watchface/editor/sample/WatchFaceConfigActivity.kt
index 9a27f0e..2fe9c01 100644
--- a/wear/wear-watchface-editor/samples/src/main/java/androidx/wear/watchface/editor/sample/WatchFaceConfigActivity.kt
+++ b/wear/wear-watchface-editor/samples/src/main/java/androidx/wear/watchface/editor/sample/WatchFaceConfigActivity.kt
@@ -93,7 +93,7 @@
                 EditorSession.createOnWatchEditingSession(
                     this@WatchFaceConfigActivity,
                     intent!!
-                )!!,
+                ),
                 object : FragmentController {
                     @SuppressLint("SyntheticAccessor")
                     override fun showConfigFragment() {
diff --git a/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditingSessionTest.kt b/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditingSessionTest.kt
index 4884ce4..fa6c96e 100644
--- a/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditingSessionTest.kt
+++ b/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditingSessionTest.kt
@@ -68,6 +68,7 @@
 import androidx.wear.watchface.complications.rendering.CanvasComplicationDrawable
 import androidx.wear.watchface.complications.rendering.ComplicationDrawable
 import androidx.wear.watchface.data.ComplicationBoundsType
+import androidx.wear.watchface.editor.EditorSession.Companion.EDITING_SESSION_TIMEOUT_MILLIS
 import androidx.wear.watchface.editor.data.EditorStateWireFormat
 import androidx.wear.watchface.style.CurrentUserStyleRepository
 import androidx.wear.watchface.style.UserStyle
@@ -79,6 +80,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.TimeoutCancellationException
 import kotlinx.coroutines.android.asCoroutineDispatcher
 import kotlinx.coroutines.async
 import kotlinx.coroutines.job
@@ -98,6 +100,7 @@
 import org.mockito.Mockito.mock
 import java.util.concurrent.CountDownLatch
 import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeUnit.MILLISECONDS
 
 public const val LEFT_COMPLICATION_ID: Int = 1000
 public const val RIGHT_COMPLICATION_ID: Int = 1001
@@ -121,6 +124,7 @@
 public open class OnWatchFaceEditingTestActivity : ComponentActivity() {
     public lateinit var editorSession: EditorSession
     public lateinit var onCreateException: Exception
+    public val creationLatch: CountDownLatch = CountDownLatch(1)
 
     public val listenableEditorSession: ListenableEditorSession by lazy {
         ListenableEditorSession(editorSession)
@@ -141,9 +145,11 @@
                     this@OnWatchFaceEditingTestActivity,
                     intent!!,
                     providerInfoRetrieverProvider!!
-                )!!
+                )
             } catch (e: Exception) {
                 >
+            } finally {
+                creationLatch.countDown()
             }
         }
     }
@@ -383,7 +389,8 @@
         watchFaceId: WatchFaceId = testInstanceId,
         previewReferenceTimeMillis: Long = 12345,
         providerInfoRetrieverProvider: ProviderInfoRetrieverProvider =
-            TestProviderInfoRetrieverProvider()
+            TestProviderInfoRetrieverProvider(),
+        shouldTimeout: Boolean = false
     ): ActivityScenario<OnWatchFaceEditingTestActivity> {
         val userStyleRepository = CurrentUserStyleRepository(UserStyleSchema(userStyleSettings))
         val complicationsManager = ComplicationsManager(complications, userStyleRepository)
@@ -411,7 +418,9 @@
                 onDestroyLatch.countDown()
             }
         }
-        WatchFace.registerEditorDelegate(testComponentName, editorDelegate)
+        if (!shouldTimeout) {
+            WatchFace.registerEditorDelegate(testComponentName, editorDelegate)
+        }
 
         OnWatchFaceEditingTestActivity.providerInfoRetrieverProvider = providerInfoRetrieverProvider
 
@@ -428,6 +437,12 @@
         )
     }
 
+    private fun createOnWatchFaceEditingTestActivityThatThrowsTimeoutException():
+        ActivityScenario<OnWatchFaceEditingTestActivity> =
+            createOnWatchFaceEditingTestActivity(
+                emptyList(), emptyList(), /* other params are default */ shouldTimeout = true
+            )
+
     @After
     public fun tearDown() {
         ComplicationProviderChooserContract.useTestComplicationHelperActivity = false
@@ -437,6 +452,15 @@
     }
 
     @Test
+    public fun createOnWatchEditingSessionThrowsTimeoutException() {
+        val scenario = createOnWatchFaceEditingTestActivityThatThrowsTimeoutException()
+        lateinit var activity: OnWatchFaceEditingTestActivity
+        scenario.onActivity { activity = it }
+        activity.creationLatch.await(EDITING_SESSION_TIMEOUT_MILLIS + 500, MILLISECONDS)
+        assert(activity.onCreateException is TimeoutCancellationException)
+    }
+
+    @Test
     public fun watchFaceComponentName() {
         val scenario = createOnWatchFaceEditingTestActivity(emptyList(), emptyList())
         scenario.onActivity {
@@ -1228,7 +1252,7 @@
             )
             assertThat(intent.getPackage()).isEqualTo(testEditorPackageName)
 
-            val editorRequest = EditorRequest.createFromIntent(intent)!!
+            val editorRequest = EditorRequest.createFromIntent(intent)
             assertThat(editorRequest.editorPackageName).isEqualTo(testEditorPackageName)
             assertThat(editorRequest.initialUserStyle).isNull()
             assertThat(editorRequest.watchFaceComponentName).isEqualTo(testComponentName)
diff --git a/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt b/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt
index 40648f6..ab064c3 100644
--- a/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt
+++ b/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt
@@ -68,6 +68,7 @@
 import kotlinx.coroutines.cancel
 import kotlinx.coroutines.withContext
 import kotlinx.coroutines.withTimeout
+import kotlin.jvm.Throws
 
 private typealias WireComplicationProviderInfo =
     android.support.wearable.complications.ComplicationProviderInfo
@@ -183,14 +184,17 @@
          * @param editIntent The [Intent] sent by SysUI to launch the editing session.
          * @return Deferred<EditorSession?> which is resolved with either the [EditorSession] or
          * `null` if it can't be constructed.
+         * @throws [TimeoutCancellationException] if it takes more than
+         * [EDITING_SESSION_TIMEOUT_MILLIS] milliseconds to create a watch face editor.
          */
         @SuppressWarnings("ExecutorRegistration")
         @JvmStatic
         @UiThread
+        @Throws(TimeoutCancellationException::class)
         public suspend fun createOnWatchEditingSession(
             activity: ComponentActivity,
             editIntent: Intent
-        ): EditorSession? = createOnWatchEditingSessionImpl(
+        ): EditorSession = createOnWatchEditingSessionImpl(
             activity,
             editIntent,
             object : ProviderInfoRetrieverProvider {
@@ -199,16 +203,17 @@
         )
 
         // Used by tests.
+        @Throws(TimeoutCancellationException::class)
         internal suspend fun createOnWatchEditingSessionImpl(
             activity: ComponentActivity,
             editIntent: Intent,
             providerInfoRetrieverProvider: ProviderInfoRetrieverProvider
-        ): EditorSession? = TraceEvent(
+        ): EditorSession = TraceEvent(
             "EditorSession.createOnWatchEditingSessionAsyncImpl"
         ).use {
             val coroutineScope =
                 CoroutineScope(Handler(Looper.getMainLooper()).asCoroutineDispatcher().immediate)
-            return EditorRequest.createFromIntent(editIntent)?.let { editorRequest ->
+            return EditorRequest.createFromIntent(editIntent).let { editorRequest ->
                 // We need to respect the lifecycle and register the ActivityResultListener now.
                 val session = OnWatchFaceEditorSessionImpl(
                     activity,
@@ -223,14 +228,15 @@
                 // [WatchFace.getOrCreateEditorDelegate] is async.
                 // Resolve only after init has been completed.
                 withContext(coroutineScope.coroutineContext) {
-                    session.setEditorDelegate(
-                        WatchFace.getOrCreateEditorDelegate(
-                            editorRequest.watchFaceComponentName
-                        ).await()
-                    )
-
-                    // Resolve only after init has been completed.
-                    session
+                    withTimeout(EDITING_SESSION_TIMEOUT_MILLIS) {
+                        session.setEditorDelegate(
+                            WatchFace.getOrCreateEditorDelegate(
+                                editorRequest.watchFaceComponentName
+                            ).await()
+                        )
+                        // Resolve only after init has been completed.
+                        session
+                    }
                 }
             }
         }
@@ -250,8 +256,8 @@
             activity: ComponentActivity,
             editIntent: Intent,
             headlessWatchFaceClient: HeadlessWatchFaceClient
-        ): EditorSession? = TraceEvent("EditorSession.createHeadlessEditingSession").use {
-            EditorRequest.createFromIntent(editIntent)?.let {
+        ): EditorSession = TraceEvent("EditorSession.createHeadlessEditingSession").use {
+            EditorRequest.createFromIntent(editIntent).let {
                 HeadlessEditorSession(
                     activity,
                     headlessWatchFaceClient,
@@ -267,6 +273,9 @@
                 )
             }
         }
+
+        /** Timeout allowed for waiting for creating the watch face editing session. */
+        public const val EDITING_SESSION_TIMEOUT_MILLIS: Long = 4000L
     }
 }
 
diff --git a/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/WatchFaceEditorContract.kt b/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/WatchFaceEditorContract.kt
index 9408e35..8a139a6 100644
--- a/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/WatchFaceEditorContract.kt
+++ b/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/WatchFaceEditorContract.kt
@@ -22,7 +22,6 @@
 import android.content.Context
 import android.content.Intent
 import android.os.Build
-import android.support.wearable.watchface.Constants
 import androidx.activity.result.contract.ActivityResultContract
 import androidx.annotation.RequiresApi
 import androidx.wear.watchface.client.EditorServiceClient
@@ -31,6 +30,8 @@
 import androidx.wear.watchface.client.WatchFaceId
 import androidx.wear.watchface.style.UserStyle
 import androidx.wear.watchface.style.UserStyleData
+import kotlinx.coroutines.TimeoutCancellationException
+import kotlin.jvm.Throws
 
 internal const val INSTANCE_ID_KEY: String = "INSTANCE_ID_KEY"
 internal const val COMPONENT_NAME_KEY: String = "COMPONENT_NAME_KEY"
@@ -82,17 +83,18 @@
         /**
          * Returns an [EditorRequest] saved to a [Intent] by [WatchFaceEditorContract.createIntent]
          * if there is one or `null` otherwise. Intended for use by the watch face editor activity.
+         * @throws [TimeoutCancellationException] in case of en error.
          */
         @SuppressLint("NewApi")
         @JvmStatic
-        public fun createFromIntent(intent: Intent): EditorRequest? {
+        @Throws(TimeoutCancellationException::class)
+        public fun createFromIntent(intent: Intent): EditorRequest {
             val componentName =
-                intent.getParcelableExtra<ComponentName>(COMPONENT_NAME_KEY)
-                    ?: intent.getParcelableExtra(Constants.EXTRA_WATCH_FACE_COMPONENT)
+                intent.getParcelableExtra<ComponentName>(COMPONENT_NAME_KEY)!!
             val editorPackageName = intent.getPackage() ?: ""
             val instanceId = WatchFaceId(intent.getStringExtra(INSTANCE_ID_KEY) ?: "")
             val userStyleKey = intent.getStringArrayExtra(USER_STYLE_KEY)
-            return componentName?.let {
+            return componentName.let {
                 if (userStyleKey != null) {
                     EditorRequest(
                         componentName,
@@ -101,8 +103,7 @@
                             HashMap<String, ByteArray>().apply {
                                 for (i in userStyleKey.indices) {
                                     val userStyleValue =
-                                        intent.getByteArrayExtra(USER_STYLE_VALUES + i)
-                                            ?: return null
+                                        intent.getByteArrayExtra(USER_STYLE_VALUES + i)!!
                                     put(userStyleKey[i], userStyleValue)
                                 }
                             }