1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/* 2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Copyright (C) 2011 The Android Open Source Project 3227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 4227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Licensed under the Apache License, Version 2.0 (the "License"); 5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * you may not use this file except in compliance with the License. 6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * You may obtain a copy of the License at 7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * http://www.apache.org/licenses/LICENSE-2.0 9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unless required by applicable law or agreed to in writing, software 11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * distributed under the License is distributed on an "AS IS" BASIS, 12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * See the License for the specific language governing permissions and 14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * limitations under the License. 15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspackage androidx.media.filterfw; 19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.util.Log; 21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport dalvik.system.PathClassLoader; 23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.lang.reflect.Constructor; 25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.HashSet; 26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspublic class FilterFactory { 28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private static FilterFactory mSharedFactory; 30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private HashSet<String> mPackages = new HashSet<String>(); 31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private static ClassLoader mCurrentClassLoader; 33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private static HashSet<String> mLibraries; 34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private static Object mClassLoaderGuard; 35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks static { 37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCurrentClassLoader = Thread.currentThread().getContextClassLoader(); 38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mLibraries = new HashSet<String>(); 39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mClassLoaderGuard = new Object(); 40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private static final String TAG = "FilterFactory"; 43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private static boolean mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE); 44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static FilterFactory sharedFactory() { 46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mSharedFactory == null) { 47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSharedFactory = new FilterFactory(); 48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mSharedFactory; 50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Adds a new Java library to the list to be scanned for filters. 54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * libraryPath must be an absolute path of the jar file. This needs to be 55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * static because only one classloader per process can open a shared native 56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * library, which a filter may well have. 57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static void addFilterLibrary(String libraryPath) { 59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mLogVerbose) Log.v(TAG, "Adding filter library " + libraryPath); 60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized(mClassLoaderGuard) { 61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mLibraries.contains(libraryPath)) { 62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mLogVerbose) Log.v(TAG, "Library already added"); 63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return; 64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mLibraries.add(libraryPath); 66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Chain another path loader to the current chain 67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCurrentClassLoader = new PathClassLoader(libraryPath, mCurrentClassLoader); 68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void addPackage(String packageName) { 72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mLogVerbose) Log.v(TAG, "Adding package " + packageName); 73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /* TODO: This should use a getPackage call in the caller's context, but no such method 74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks exists. 75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Package pkg = Package.getPackage(packageName); 76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (pkg == null) { 77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new IllegalArgumentException("Unknown filter package '" + packageName + "'!"); 78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPackages.add(packageName); 81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public boolean isFilterAvailable(String className) { 84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return getFilterClass(className) != null; 85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public Filter createFilterByClassName(String className, String filterName, MffContext context) { 88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mLogVerbose) Log.v(TAG, "Looking up class " + className); 89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Class<? extends Filter> filterClass = getFilterClass(className); 90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (filterClass == null) { 91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new IllegalArgumentException("Unknown filter class '" + className + "'!"); 92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return createFilterByClass(filterClass, filterName, context); 94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public Filter createFilterByClass(Class<? extends Filter> filterClass, 97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks String filterName, MffContext context) { 98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Look for the correct constructor 99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Constructor<? extends Filter> filterConstructor = null; 100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks filterConstructor = filterClass.getConstructor(MffContext.class, String.class); 102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (NoSuchMethodException e) { 103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new IllegalArgumentException("The filter class '" + filterClass 104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks + "' does not have a constructor of the form <init>(MffContext, String)!"); 105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Construct the filter 108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Filter filter = null; 109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks filter = filterConstructor.newInstance(context, filterName); 111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (Throwable t) { 112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Error creating filter " + filterName + "!", t); 113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (filter == null) { 116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new IllegalArgumentException("Could not construct the filter '" 117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks + filterName + "'!"); 118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return filter; 120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private Class<? extends Filter> getFilterClass(String name) { 123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Class<?> filterClass = null; 124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Look for the class in the imported packages 126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (String packageName : mPackages) { 127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mLogVerbose) Log.v(TAG, "Trying "+ packageName + "." + name); 129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized(mClassLoaderGuard) { 130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks filterClass = mCurrentClassLoader.loadClass(packageName + "." + name); 131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (ClassNotFoundException e) { 133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks continue; 134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Exit loop if class was found. 136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (filterClass != null) { 137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Class<? extends Filter> result = null; 141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (filterClass != null) { 143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks result = filterClass.asSubclass(Filter.class); 144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (ClassCastException e) { 146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Leave result == null 147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return result; 149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks} 151