/* * Copyright (C) 2015 Fumihiro Xue * Copyright (C) 2014 Lucas Rocha * * 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 view_inspector.probe; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import java.io.IOException; import java.lang.reflect.Modifier; import view_inspector.ViewInspector; import static view_inspector.probe.ViewClassUtil.findViewClass; /** * {@link LayoutInflater.Factory2} used by a {@link Probe} instance to * inflate layout resources. It will wrap target {@link View}s with dynamic * proxy classes that redirect their method calls to an {@link Interceptor}. * * @see Interceptor * @see ViewProxyBuilder */ class ProbeViewFactory implements LayoutInflater.Factory2 { private static final String TAG_FRAGMENT = "fragment"; private static final String TAG_INTERNAL_CLASS = "com.android.internal"; private static final String TAG_INTERNAL_CLASS_SUPPORT_V7 = "android.support.v7.internal"; private static final String TAG_VIEW_STUB = "ViewStub"; private static final String TAG_VIEW_INSPECTOR = "view_inspector"; private final Context mContext; private final Probe mProbe; ProbeViewFactory(Context context, Probe probe) { mContext = context; mProbe = probe; } private View createProxyView(Context context, String name, AttributeSet attrs) throws ClassNotFoundException { try { final Class<?> viewClass = findViewClass(mContext, name); // Probe can't wrap final or abstract View classes, just bail. final int modifiers = viewClass.getModifiers(); if (Modifier.isFinal(modifiers) || Modifier.isAbstract(modifiers)) { return null; } return ViewProxyBuilder.forClass(context, viewClass) .constructorArgValues(mContext, attrs) .interceptor(mProbe.getInterceptor()) .build(); } catch (ClassCastException e) { // Not a View subclass, just bail. return null; } catch (IOException e) { throw new IllegalStateException("Failed to create View proxy", e); } } @Override public View onCreateView(View parent, String name, Context context, AttributeSet attrs) { Log.d(ViewInspector.TAG, "ProbeViewFactory > onCreateView > name = " + name); if (name.equals(TAG_FRAGMENT) || name.startsWith(TAG_INTERNAL_CLASS) || name.startsWith(TAG_INTERNAL_CLASS_SUPPORT_V7) || name.contains(TAG_VIEW_STUB) || name.startsWith(TAG_VIEW_INSPECTOR)) { Log.d(ViewInspector.TAG, "ProbeViewFactory > view skipped."); return null; } try { return createProxyView(context, name, attrs); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } @Override public View onCreateView(String name, Context context, AttributeSet attrs) { return onCreateView(null, name, context, attrs); } }