<lambda>null1 package com.android.wallpaper.util.wallpaperconnection
2
3 import android.app.Flags.liveWallpaperContentHandling
4 import android.app.WallpaperColors
5 import android.app.WallpaperInfo
6 import android.app.wallpaper.WallpaperDescription
7 import android.graphics.Point
8 import android.graphics.Rect
9 import android.graphics.RectF
10 import android.os.Bundle
11 import android.os.IBinder
12 import android.os.ParcelFileDescriptor
13 import android.os.RemoteException
14 import android.service.wallpaper.IWallpaperConnection
15 import android.service.wallpaper.IWallpaperEngine
16 import android.service.wallpaper.IWallpaperService
17 import android.util.Log
18 import android.view.SurfaceView
19 import android.view.WindowManager
20 import com.android.wallpaper.util.WallpaperConnection
21 import com.android.wallpaper.util.WallpaperConnection.WhichPreview
22 import java.lang.reflect.InvocationTargetException
23 import kotlinx.coroutines.CancellableContinuation
24 import kotlinx.coroutines.suspendCancellableCoroutine
25
26 class WallpaperEngineConnection(
27 private val displayMetrics: Point,
28 private val whichPreview: WhichPreview,
29 ) : IWallpaperConnection.Stub() {
30
31 var engine: IWallpaperEngine? = null
32 private var engineContinuation: CancellableContinuation<IWallpaperEngine>? = null
33 private var listener: WallpaperEngineConnectionListener? = null
34
35 suspend fun getEngine(
36 wallpaperService: IWallpaperService,
37 destinationFlag: Int,
38 surfaceView: SurfaceView,
39 description: WallpaperDescription,
40 ): IWallpaperEngine {
41 return engine
42 ?: suspendCancellableCoroutine { k: CancellableContinuation<IWallpaperEngine> ->
43 engineContinuation = k
44 attachEngineConnection(
45 wallpaperEngineConnection = this,
46 wallpaperService = wallpaperService,
47 destinationFlag = destinationFlag,
48 surfaceView = surfaceView,
49 description = description,
50 )
51 }
52 }
53
54 override fun attachEngine(engine: IWallpaperEngine?, displayId: Int) {
55 // Note that the engine in attachEngine callback is different from the one in engineShown
56 // callback, which is called after this attachEngine callback. We use the engine reference
57 // passed in attachEngine callback for WallpaperEngineConnection.
58 this.engine = engine
59 engine?.apply {
60 setVisibility(true)
61 resizePreview(Rect(0, 0, displayMetrics.x, displayMetrics.y))
62 requestWallpaperColors()
63 }
64 }
65
66 override fun engineShown(engine: IWallpaperEngine?) {
67 if (engine != null) {
68 dispatchWallpaperCommand(engine)
69 // Note that the engines from the attachEngine and engineShown callbacks are different
70 // and we only use the reference of engine from the attachEngine callback.
71 this.engine?.let { engineContinuation?.resumeWith(Result.success(it)) }
72 }
73 }
74
75 private fun dispatchWallpaperCommand(engine: IWallpaperEngine) {
76 val bundle = Bundle()
77 bundle.putInt(WHICH_PREVIEW, whichPreview.value)
78 try {
79 engine.dispatchWallpaperCommand(COMMAND_PREVIEW_INFO, 0, 0, 0, bundle)
80 } catch (e: RemoteException) {
81 Log.e(TAG, "Error dispatching wallpaper command: $whichPreview")
82 }
83 }
84
85 override fun onLocalWallpaperColorsChanged(
86 area: RectF?,
87 colors: WallpaperColors?,
88 displayId: Int,
89 ) {
90 // Do nothing intended.
91 }
92
93 override fun onWallpaperColorsChanged(colors: WallpaperColors?, displayId: Int) {
94 listener?.onWallpaperColorsChanged(colors, displayId)
95 }
96
97 override fun setWallpaper(name: String?): ParcelFileDescriptor {
98 TODO("Not yet implemented")
99 }
100
101 fun setListener(listener: WallpaperEngineConnectionListener) {
102 this.listener = listener
103 }
104
105 fun removeListener() {
106 this.listener = null
107 }
108
109 companion object {
110 const val TAG = "WallpaperEngineConnection"
111
112 const val COMMAND_PREVIEW_INFO = "android.wallpaper.previewinfo"
113 const val WHICH_PREVIEW = "which_preview"
114
115 /*
116 * Tries to call the attach method used in Android 14(U) and earlier, returning true on
117 * success otherwise false.
118 */
119 private fun tryPreUAttach(
120 wallpaperEngineConnection: WallpaperEngineConnection,
121 wallpaperService: IWallpaperService,
122 destinationFlag: Int,
123 surfaceView: SurfaceView,
124 ): Boolean {
125 try {
126 val method =
127 wallpaperService.javaClass.getMethod(
128 "attach",
129 IWallpaperConnection::class.java,
130 IBinder::class.java,
131 Int::class.javaPrimitiveType,
132 Boolean::class.javaPrimitiveType,
133 Int::class.javaPrimitiveType,
134 Int::class.javaPrimitiveType,
135 Rect::class.java,
136 Int::class.javaPrimitiveType,
137 Int::class.javaPrimitiveType,
138 )
139 method.invoke(
140 wallpaperService,
141 wallpaperEngineConnection,
142 surfaceView.windowToken,
143 WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA,
144 true,
145 surfaceView.width,
146 surfaceView.height,
147 Rect(0, 0, 0, 0),
148 surfaceView.display.displayId,
149 destinationFlag,
150 )
151 return true
152 } catch (e: Exception) {
153 when (e) {
154 is NoSuchMethodException,
155 is InvocationTargetException,
156 is IllegalAccessException -> {
157 if (liveWallpaperContentHandling()) {
158 Log.w(
159 TAG,
160 "live wallpaper content handling enabled, but pre-U attach method called",
161 )
162 }
163 return false
164 }
165
166 else -> throw e
167 }
168 }
169 }
170
171 /*
172 * Tries to call the attach method used in Android 16(B) and earlier, returning true on
173 * success otherwise false.
174 */
175 private fun tryPreBAttach(
176 wallpaperEngineConnection: WallpaperEngineConnection,
177 wallpaperService: IWallpaperService,
178 destinationFlag: Int,
179 surfaceView: SurfaceView,
180 ): Boolean {
181 try {
182 val method =
183 wallpaperService.javaClass.getMethod(
184 "attach",
185 IWallpaperConnection::class.java,
186 IBinder::class.java,
187 Int::class.javaPrimitiveType,
188 Boolean::class.javaPrimitiveType,
189 Int::class.javaPrimitiveType,
190 Int::class.javaPrimitiveType,
191 Rect::class.java,
192 Int::class.javaPrimitiveType,
193 Int::class.javaPrimitiveType,
194 WallpaperInfo::class.java,
195 )
196 method.invoke(
197 wallpaperService,
198 wallpaperEngineConnection,
199 surfaceView.windowToken,
200 WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA,
201 true,
202 surfaceView.width,
203 surfaceView.height,
204 Rect(0, 0, 0, 0),
205 surfaceView.display.displayId,
206 destinationFlag,
207 null,
208 )
209 return true
210 } catch (e: Exception) {
211 when (e) {
212 is NoSuchMethodException,
213 is InvocationTargetException,
214 is IllegalAccessException -> {
215 if (liveWallpaperContentHandling()) {
216 Log.w(
217 TAG,
218 "live wallpaper content handling enabled, but pre-B attach method called",
219 )
220 }
221 return false
222 }
223
224 else -> throw e
225 }
226 }
227 }
228
229 /*
230 * This method tries to call historical versions of IWallpaperService#attach since this code
231 * may be running against older versions of Android. We have no control over what versions
232 * of Android third party users of this code will be running.
233 */
234 private fun attachEngineConnection(
235 wallpaperEngineConnection: WallpaperEngineConnection,
236 wallpaperService: IWallpaperService,
237 destinationFlag: Int,
238 surfaceView: SurfaceView,
239 description: WallpaperDescription,
240 ) {
241 if (
242 tryPreUAttach(
243 wallpaperEngineConnection,
244 wallpaperService,
245 destinationFlag,
246 surfaceView,
247 )
248 ) {
249 return
250 }
251 if (
252 tryPreBAttach(
253 wallpaperEngineConnection,
254 wallpaperService,
255 destinationFlag,
256 surfaceView,
257 )
258 ) {
259 return
260 }
261
262 wallpaperService.attach(
263 wallpaperEngineConnection,
264 surfaceView.windowToken,
265 WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA,
266 true,
267 surfaceView.width,
268 surfaceView.height,
269 Rect(0, 0, 0, 0),
270 surfaceView.display.displayId,
271 destinationFlag,
272 null,
273 description,
274 )
275 }
276 }
277
278 /** Interface to be notified of connect/disconnect events from [WallpaperConnection] */
279 interface WallpaperEngineConnectionListener {
280 /** Called after the wallpaper color is available or updated. */
281 fun onWallpaperColorsChanged(colors: WallpaperColors?, displayId: Int) {}
282 }
283 }
284