001/** 002 * Copyright 2010-2016 Boxfuse GmbH 003 * <p/> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p/> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p/> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.avaje.classpath.scanner.internal.scanner.classpath.android; 017 018import android.content.Context; 019import dalvik.system.DexFile; 020import dalvik.system.PathClassLoader; 021import org.avaje.classpath.scanner.core.ClassPathScanException; 022import org.avaje.classpath.scanner.core.Location; 023import org.avaje.classpath.scanner.ClassFilter; 024import org.avaje.classpath.scanner.ResourceFilter; 025import org.avaje.classpath.scanner.Resource; 026import org.avaje.classpath.scanner.andriod.ContextHolder; 027import org.avaje.classpath.scanner.internal.ResourceAndClassScanner; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031import java.io.IOException; 032import java.util.ArrayList; 033import java.util.Enumeration; 034import java.util.List; 035 036/** 037 * Class & resource scanner for Android. 038 */ 039public class AndroidScanner implements ResourceAndClassScanner { 040 041 private static final Logger LOG = LoggerFactory.getLogger(AndroidScanner.class); 042 043 private final Context context; 044 045 private final PathClassLoader classLoader; 046 047 public AndroidScanner(ClassLoader classLoader) { 048 this.classLoader = (PathClassLoader) classLoader; 049 context = ContextHolder.getContext(); 050 if (context == null) { 051 throw new ClassPathScanException("Unable to create scanner. " + 052 "Within an activity you can fix this with org.avaje.classpath.scanner.android.ContextHolder.setContext(this);"); 053 } 054 } 055 056 public List<Resource> scanForResources(Location location, ResourceFilter predicate) { 057 058 try { 059 List<Resource> resources = new ArrayList<Resource>(); 060 String path = location.getPath(); 061 for (String asset : context.getAssets().list(path)) { 062 if (predicate.isMatch(asset)) { 063 resources.add(new AndroidResource(context.getAssets(), path, asset)); 064 } 065 } 066 067 return resources; 068 069 } catch (IOException e) { 070 throw new ClassPathScanException(e); 071 } 072 } 073 074 public List<Class<?>> scanForClasses(Location location, ClassFilter predicate) { 075 076 try { 077 078 String pkg = location.getPath().replace("/", "."); 079 080 List<Class<?>> classes = new ArrayList<Class<?>>(); 081 082 DexFile dex = new DexFile(context.getApplicationInfo().sourceDir); 083 Enumeration<String> entries = dex.entries(); 084 while (entries.hasMoreElements()) { 085 String className = entries.nextElement(); 086 if (className.startsWith(pkg)) { 087 Class<?> clazz = classLoader.loadClass(className); 088 if (predicate.isMatch(clazz)) { 089 classes.add(clazz); 090 LOG.trace("... found class: {}", className); 091 } 092 } 093 } 094 return classes; 095 096 } catch (IOException e) { 097 throw new ClassPathScanException(e); 098 099 } catch (ClassNotFoundException e) { 100 throw new ClassPathScanException(e); 101 } 102 } 103}