blob: 9cdf97cfc17b823133efe41f03cab8f7009afbae [file] [log] [blame]
Alex Clarkec121e642021-09-07 22:17:51 +01001/*
2 * Copyright 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Alex Clarke90add702022-03-25 15:18:16 +000017package androidx.wear.watchface
Alex Clarkec121e642021-09-07 22:17:51 +010018
19import android.app.Service
20import android.content.Context
21import android.content.Intent
22import android.graphics.Bitmap
23import android.graphics.Canvas
24import android.graphics.Rect
25import android.graphics.SurfaceTexture
26import android.os.Build
27import android.os.Handler
28import android.os.IBinder
29import android.os.Looper
30import android.view.Surface
31import android.view.SurfaceHolder
32import androidx.annotation.RequiresApi
33import androidx.test.core.app.ApplicationProvider
34import androidx.wear.watchface.client.WatchFaceControlClient
35import androidx.wear.watchface.control.IWatchFaceInstanceServiceStub
36import androidx.wear.watchface.control.WatchFaceControlService
37import kotlinx.coroutines.CoroutineScope
38import kotlinx.coroutines.Deferred
39import kotlinx.coroutines.android.asCoroutineDispatcher
40import kotlinx.coroutines.launch
41import kotlinx.coroutines.runBlocking
42import org.junit.Before
43import org.mockito.Mockito
44import java.util.concurrent.CountDownLatch
45import java.util.concurrent.TimeUnit
46import java.util.concurrent.TimeoutException
Alex Clarke12ca62e2022-04-25 22:33:22 +010047import kotlinx.coroutines.MainScope
Alex Clarkec121e642021-09-07 22:17:51 +010048
49internal const val TIMEOUT_MILLIS = 1000L
50
51/**
52 * Test shim to allow us to connect to WatchFaceControlService from a test and to optionally
53 * override the reported API version.
54 */
Alex Clarke90add702022-03-25 15:18:16 +000055@RequiresApi(Build.VERSION_CODES.O_MR1)
Alex Clarkec121e642021-09-07 22:17:51 +010056public class WatchFaceControlTestService : Service() {
57 public companion object {
58 /**
59 * If non-null this overrides the API version reported by [IWatchFaceInstanceServiceStub].
60 */
61 public var apiVersionOverride: Int? = null
62 }
63
64 private val realService = object : WatchFaceControlService() {
65 override fun createServiceStub(): IWatchFaceInstanceServiceStub =
Alex Clarkeb1e0b142022-02-11 19:51:30 +000066 object : IWatchFaceInstanceServiceStub(
67 ApplicationProvider.getApplicationContext<Context>(),
Alex Clarke12ca62e2022-04-25 22:33:22 +010068 MainScope()
Alex Clarkeb1e0b142022-02-11 19:51:30 +000069 ) {
Alex Clarkec121e642021-09-07 22:17:51 +010070 @RequiresApi(Build.VERSION_CODES.O_MR1)
71 override fun getApiVersion(): Int = apiVersionOverride ?: super.getApiVersion()
72 }
73
74 init {
75 setContext(ApplicationProvider.getApplicationContext<Context>())
76 }
77 }
78
79 @RequiresApi(Build.VERSION_CODES.O_MR1)
80 override fun onBind(intent: Intent?): IBinder? = realService.onBind(intent)
81}
82
83/** Base class for the various async tests. */
Alex Clarke90add702022-03-25 15:18:16 +000084@RequiresApi(Build.VERSION_CODES.O_MR1)
Alex Clarkec121e642021-09-07 22:17:51 +010085public open class WatchFaceControlClientServiceTest {
86 val context = ApplicationProvider.getApplicationContext<Context>()
87 val handler = Handler(Looper.getMainLooper())
88 val handlerCoroutineScope = CoroutineScope(handler.asCoroutineDispatcher().immediate)
89
90 val surfaceHolder = Mockito.mock(SurfaceHolder::class.java)
91 val surface = Mockito.mock(Surface::class.java)
92 val renderLatch = CountDownLatch(1)
93
94 val surfaceTexture = SurfaceTexture(false)
95 val glSurface = Surface(surfaceTexture)
96 val glSurfaceHolder = Mockito.mock(SurfaceHolder::class.java)
97
98 val watchFaceControlClientService = runBlocking {
99 WatchFaceControlClient.createWatchFaceControlClientImpl(
100 context,
101 Intent(context, WatchFaceControlTestService::class.java).apply {
102 action = WatchFaceControlService.ACTION_WATCHFACE_CONTROL_SERVICE
103 }
104 )
105 }
106
107 @Before
108 fun setUp() {
109 Mockito.`when`(surfaceHolder.surfaceFrame).thenReturn(Rect(0, 0, 100, 100))
110 Mockito.`when`(surfaceHolder.surface).thenReturn(surface)
111 Mockito.`when`(surface.isValid).thenReturn(false)
112 val bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
113 val canvas = Canvas(bitmap)
114 Mockito.`when`(surfaceHolder.lockHardwareCanvas()).thenReturn(canvas)
115
116 Mockito.`when`(surfaceHolder.unlockCanvasAndPost(canvas)).then {
117 renderLatch.countDown()
118 }
119
120 surfaceTexture.setDefaultBufferSize(10, 10)
121 Mockito.`when`(glSurfaceHolder.surface).thenReturn(glSurface)
122 Mockito.`when`(glSurfaceHolder.surfaceFrame)
123 .thenReturn(Rect(0, 0, 10, 10))
124 }
125
126 fun <X> awaitWithTimeout(
127 thing: Deferred<X>,
128 timeoutMillis: Long = TIMEOUT_MILLIS
129 ): X {
130 var value: X? = null
131 val latch = CountDownLatch(1)
132 handlerCoroutineScope.launch {
133 value = thing.await()
134 latch.countDown()
135 }
136 if (!latch.await(timeoutMillis, TimeUnit.MILLISECONDS)) {
137 throw TimeoutException("Timeout waiting for thing!")
138 }
139 return value!!
140 }
141}