blob: 1d6166f3d2fd3d5c911ad510b755682fccc789b6 [file] [log] [blame]
/*
* Copyright (C) 2020 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 com.android.car.ui.pluginsupport;
import static com.android.car.ui.core.CarUi.MIN_TARGET_API;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.android.car.ui.plugin.oemapis.PluginFactoryOEMV1;
import com.android.car.ui.plugin.oemapis.PluginFactoryOEMV2;
import com.android.car.ui.plugin.oemapis.PluginVersionProviderOEMV1;
/**
* Helper class for accessing oem-apis without reflection.
*
* Because this class creates adapters, and adapters implement OEM APIs, this class cannot
* be created with the app's classloader. You must use {@link AdapterClassLoader} to load it
* so that both the app and plugin's classes can be loaded from this class.
*/
@RequiresApi(MIN_TARGET_API)
final class OemApiUtil {
private static final String TAG = "carui";
/**
* Given a plugin's context, return it's implementation of {@link PluginFactory}.
*
* This is done by asking the plugin's {@link PluginVersionProvider} for a
* factory object, and checking if it's instanceof each version of
* {@link PluginFactoryOEMV1}, casting to the correct one when found.
*
* @param pluginContext The plugin's context. This context will return
* the plugin's classloader from
* {@link Context#getClassLoader()}.
* @param appPackageName The package name of the application. This is passed to the plugin
* so that it can provide unique customizations per-app.
* @return A {@link PluginFactory}
*/
@SuppressLint("PrivateApi")
static PluginFactory getPluginFactory(
Context pluginContext, String appPackageName) {
Object oemVersionProvider = null;
try {
oemVersionProvider = Class
.forName("com.android.car.ui.plugin.PluginVersionProviderImpl")
.getDeclaredConstructor()
.newInstance();
} catch (ClassNotFoundException e) {
Log.i(TAG, "PluginVersionProviderImpl not found.", e);
} catch (ReflectiveOperationException e) {
Log.e(TAG, "PluginVersionProviderImpl could not be instantiated!", e);
}
// Add new version providers in an if-else chain here, in descending version order so
// that higher versions are preferred.
PluginVersionProvider versionProvider = null;
if (oemVersionProvider instanceof PluginVersionProviderOEMV1) {
versionProvider = new PluginVersionProviderAdapterV1(
(PluginVersionProviderOEMV1) oemVersionProvider);
} else {
Log.e(TAG, "PluginVersionProviderImpl was not instanceof any known "
+ "versions of PluginVersionProviderOEMV#.");
}
PluginFactory oemPluginFactory = null;
if (versionProvider != null) {
Object factory = versionProvider.getPluginFactory(
1, pluginContext, appPackageName);
if (factory instanceof PluginFactoryOEMV1) {
oemPluginFactory = new PluginFactoryAdapterV1(
(PluginFactoryOEMV1) factory);
} else if (classExists(
"com.android.car.ui.plugin.oemapis.PluginFactoryOEMV2")
&& factory instanceof PluginFactoryOEMV2) {
oemPluginFactory = new PluginFactoryAdapterV2(
(PluginFactoryOEMV2) factory);
} else {
Log.e(TAG, "PluginVersionProvider found, but did not provide a"
+ " factory implementing any known interfaces!");
}
}
return oemPluginFactory;
}
private static boolean classExists(@Nullable String className) {
if (className == null) {
return false;
}
try {
Class.forName(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
private OemApiUtil() {}
}