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