1 /*
<lambda>null2  * Copyright (C) 2023 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 
17 package com.google.android.torus.core.activity
18 
19 import android.annotation.SuppressLint
20 import android.content.Context
21 import android.content.pm.ActivityInfo
22 import android.content.res.Configuration
23 import android.os.Bundle
24 import android.view.SurfaceHolder
25 import android.view.SurfaceView
26 import androidx.appcompat.app.AppCompatActivity
27 import com.google.android.torus.core.content.ConfigurationChangeListener
28 import com.google.android.torus.core.engine.TorusEngine
29 import com.google.android.torus.core.engine.listener.TorusTouchListener
30 
31 /**
32  * Helper activity to show a [TorusEngine] into a [SurfaceView]. To use it, you should override
33  * [getWallpaperEngine] and return an instance of your[TorusEngine] that will draw inside the
34  * given surface.
35  *
36  * Note: [TorusViewerActivity] subclasses must include the following attribute/s
37  * in the AndroidManifest.xml:
38  * - android:configChanges="uiMode"
39  */
40 abstract class TorusViewerActivity : AppCompatActivity() {
41     private lateinit var wallpaperEngine: TorusEngine
42     private lateinit var surfaceView: SurfaceView
43 
44     /**
45      * Must be implemented to return a new instance of [TorusEngine].
46      */
47     abstract fun getWallpaperEngine(context: Context, surfaceView: SurfaceView): TorusEngine
48 
49     @SuppressLint("ClickableViewAccessibility")
50     override fun onCreate(savedInstanceState: Bundle?) {
51         super.onCreate(savedInstanceState)
52 
53         // Check that class includes the proper attributes in the AndroidManifest.xml
54         checkManifestAttributes()
55 
56         surfaceView = SurfaceView(this).apply { setContentView(this) }
57         wallpaperEngine = getWallpaperEngine(this, surfaceView)
58         wallpaperEngine.create()
59         surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
60             override fun surfaceChanged(
61                 holder: SurfaceHolder,
62                 format: Int,
63                 width: Int,
64                 height: Int
65             ) {
66                 wallpaperEngine.resize(width, height)
67             }
68 
69             override fun surfaceDestroyed(holder: SurfaceHolder) {
70             }
71 
72             override fun surfaceCreated(holder: SurfaceHolder) {
73             }
74         })
75 
76         // Pass the touch events.
77         if (wallpaperEngine is TorusTouchListener) {
78             surfaceView.setOnTouchListener { _, event ->
79                 (wallpaperEngine as TorusTouchListener).onTouchEvent(event)
80                 true
81             }
82         }
83     }
84 
85     override fun onResume() {
86         super.onResume()
87         wallpaperEngine.resume()
88     }
89 
90     override fun onPause() {
91         super.onPause()
92         wallpaperEngine.pause()
93     }
94 
95     override fun onDestroy() {
96         super.onDestroy()
97         wallpaperEngine.destroy()
98     }
99 
100     override fun onConfigurationChanged(newConfig: Configuration) {
101         super.onConfigurationChanged(newConfig)
102 
103         if (wallpaperEngine is ConfigurationChangeListener) {
104             (wallpaperEngine as ConfigurationChangeListener).onConfigurationChanged(newConfig)
105         }
106     }
107 
108     private fun checkManifestAttributes() {
109         val configChange = packageManager.getActivityInfo(componentName, 0).configChanges
110 
111         // Check if Activity sets android:configChanges="uiMode" in the manifest.
112         if ((configChange and ActivityInfo.CONFIG_UI_MODE) != ActivityInfo.CONFIG_UI_MODE) {
113             throw RuntimeException(
114                 "${TorusViewerActivity::class.simpleName} " +
115                         "has to include the attribute android:configChanges=\"uiMode\" " +
116                         "in the AndroidManifest.xml"
117             )
118         }
119     }
120 }
121