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 io.avaje.classpath.scanner.internal.scanner.classpath.android; 017 018import android.content.Context; 019import dalvik.system.DexFile; 020import dalvik.system.PathClassLoader; 021import io.avaje.classpath.scanner.Resource; 022import io.avaje.classpath.scanner.core.AndriodContextHolder; 023import io.avaje.classpath.scanner.core.Location; 024import io.avaje.classpath.scanner.internal.ScanLog; 025import io.avaje.classpath.scanner.internal.ResourceAndClassScanner; 026 027import java.io.IOException; 028import java.io.UncheckedIOException; 029import java.util.ArrayList; 030import java.util.Enumeration; 031import java.util.List; 032import java.util.function.Predicate; 033 034/** 035 * Class & resource scanner for Android. 036 */ 037public class AndroidScanner implements ResourceAndClassScanner { 038 039 private final Context context; 040 041 private final PathClassLoader classLoader; 042 043 public AndroidScanner(ClassLoader classLoader) { 044 this.classLoader = (PathClassLoader) classLoader; 045 context = AndriodContextHolder.getContext(); 046 if (context == null) { 047 throw new IllegalStateException("Unable to create scanner. Within an activity fix this with io.avaje.classpath.scanner.android.ContextHolder.setContext(this);"); 048 } 049 } 050 051 public List<Resource> scanForResources(Location location, Predicate<String> predicate) { 052 try { 053 List<Resource> resources = new ArrayList<>(); 054 String path = location.path(); 055 for (String asset : context.getAssets().list(path)) { 056 if (predicate.test(asset)) { 057 resources.add(new AndroidResource(context.getAssets(), path, asset)); 058 } 059 } 060 return resources; 061 } catch (IOException e) { 062 throw new UncheckedIOException(e); 063 } 064 } 065 066 public List<Class<?>> scanForClasses(Location location, Predicate<Class<?>> predicate) { 067 try { 068 String pkg = location.path().replace("/", "."); 069 List<Class<?>> classes = new ArrayList<>(); 070 DexFile dex = new DexFile(context.getApplicationInfo().sourceDir); 071 Enumeration<String> entries = dex.entries(); 072 while (entries.hasMoreElements()) { 073 String className = entries.nextElement(); 074 if (className.startsWith(pkg)) { 075 Class<?> clazz = classLoader.loadClass(className); 076 if (predicate.test(clazz)) { 077 classes.add(clazz); 078 ScanLog.log.trace("found {}", className); 079 } 080 } 081 } 082 return classes; 083 084 } catch (IOException | ClassNotFoundException e) { 085 throw new RuntimeException(e); 086 } 087 } 088}