ActivityHolderProxyFactory.kt
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.privacysandbox.sdkruntime.client.loader.impl.injector
import android.app.Activity
import androidx.privacysandbox.sdkruntime.core.activity.ActivityHolder
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy
/**
* Create proxy of [ActivityHolder] that implements same interface loaded by SDK Classloader.
*/
internal class ActivityHolderProxyFactory private constructor(
private val sdkClassLoader: ClassLoader,
private val activityHolderClass: Class<*>,
private val backPressedDispatcherProxyFactory: BackPressedDispatcherProxyFactory,
private val lifecycleRegistryProxyFactory: LifecycleRegistryProxyFactory,
) {
fun createProxyFor(activityHolder: ActivityHolder): Any {
val dispatcherProxy = backPressedDispatcherProxyFactory.setupOnBackPressedDispatcherProxy(
activityHolder.getOnBackPressedDispatcher()
)
val handler = ActivityHolderHandler(
activityHolder.getActivity(),
dispatcherProxy
)
val activityHolderProxy = Proxy.newProxyInstance(
sdkClassLoader,
arrayOf(activityHolderClass),
handler
)
val lifecycleProxy = lifecycleRegistryProxyFactory.setupLifecycleProxy(
activityHolderProxy,
activityHolder.lifecycle
)
handler.lifecycleProxy = lifecycleProxy
return activityHolderProxy
}
private class ActivityHolderHandler(
private val activity: Activity,
private val onBackPressedDispatcherProxy: Any,
) : InvocationHandler {
var lifecycleProxy: Any? = null
override fun invoke(proxy: Any, method: Method, args: Array<out Any?>?): Any {
return when (method.name) {
"equals" -> proxy === args?.get(0)
"hashCode" -> hashCode()
"toString" -> toString()
"getActivity" -> activity
"getOnBackPressedDispatcher" -> onBackPressedDispatcherProxy
"getLifecycle" -> lifecycleProxy!!
else -> {
throw UnsupportedOperationException(
"Unexpected method call object:$proxy, method: $method, args: $args"
)
}
}
}
}
companion object {
fun createFor(classLoader: ClassLoader): ActivityHolderProxyFactory {
val activityHolderClass = Class.forName(
ActivityHolder::class.java.name,
/* initialize = */ false,
classLoader
)
val lifecycleRegistryProxyFactory = LifecycleRegistryProxyFactory.createFor(classLoader)
val backPressedDispatcherProxyFactory =
BackPressedDispatcherProxyFactory.createFor(classLoader)
return ActivityHolderProxyFactory(
sdkClassLoader = classLoader,
activityHolderClass = activityHolderClass,
backPressedDispatcherProxyFactory = backPressedDispatcherProxyFactory,
lifecycleRegistryProxyFactory = lifecycleRegistryProxyFactory
)
}
}
}