1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.util; 18 19 import android.content.Context; 20 import android.util.ArrayMap; 21 import android.util.AttributeSet; 22 import android.view.InflateException; 23 import android.view.LayoutInflater; 24 import android.view.View; 25 26 import com.android.systemui.dagger.SysUISingleton; 27 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; 28 29 import java.lang.reflect.InvocationTargetException; 30 import java.lang.reflect.Method; 31 import java.lang.reflect.Modifier; 32 33 import javax.inject.Inject; 34 import javax.inject.Named; 35 36 import dagger.BindsInstance; 37 import dagger.Subcomponent; 38 39 /** 40 * Manages inflation that requires dagger injection. 41 * See docs/dagger.md for details. 42 */ 43 @SysUISingleton 44 public class InjectionInflationController { 45 46 public static final String VIEW_CONTEXT = "view_context"; 47 private final ArrayMap<String, Method> mInjectionMap = new ArrayMap<>(); 48 private final LayoutInflater.Factory2 mFactory = new InjectionFactory(); 49 private final ViewInstanceCreator.Factory mViewInstanceCreatorFactory; 50 51 @Inject InjectionInflationController(ViewInstanceCreator.Factory viewInstanceCreatorFactory)52 public InjectionInflationController(ViewInstanceCreator.Factory viewInstanceCreatorFactory) { 53 mViewInstanceCreatorFactory = viewInstanceCreatorFactory; 54 initInjectionMap(); 55 } 56 57 /** 58 * Wraps a {@link LayoutInflater} to support creating dagger injected views. 59 * See docs/dagger.md for details. 60 */ injectable(LayoutInflater inflater)61 public LayoutInflater injectable(LayoutInflater inflater) { 62 LayoutInflater ret = inflater.cloneInContext(inflater.getContext()); 63 ret.setPrivateFactory(mFactory); 64 return ret; 65 } 66 initInjectionMap()67 private void initInjectionMap() { 68 for (Method method : ViewInstanceCreator.class.getDeclaredMethods()) { 69 if (View.class.isAssignableFrom(method.getReturnType()) 70 && (method.getModifiers() & Modifier.PUBLIC) != 0) { 71 mInjectionMap.put(method.getReturnType().getName(), method); 72 } 73 } 74 } 75 76 /** 77 * Subcomponent that actually creates injected views. 78 */ 79 @Subcomponent 80 public interface ViewInstanceCreator { 81 82 /** Factory for creating a ViewInstanceCreator. */ 83 @Subcomponent.Factory 84 interface Factory { build( @indsInstance @amedVIEW_CONTEXT) Context context, @BindsInstance AttributeSet attributeSet)85 ViewInstanceCreator build( 86 @BindsInstance @Named(VIEW_CONTEXT) Context context, 87 @BindsInstance AttributeSet attributeSet); 88 } 89 90 /** 91 * Creates the NotificationStackScrollLayout. 92 */ createNotificationStackScrollLayout()93 NotificationStackScrollLayout createNotificationStackScrollLayout(); 94 } 95 96 97 private class InjectionFactory implements LayoutInflater.Factory2 { 98 99 @Override onCreateView(String name, Context context, AttributeSet attrs)100 public View onCreateView(String name, Context context, AttributeSet attrs) { 101 Method creationMethod = mInjectionMap.get(name); 102 if (creationMethod != null) { 103 try { 104 return (View) creationMethod.invoke( 105 mViewInstanceCreatorFactory.build(context, attrs)); 106 } catch (IllegalAccessException e) { 107 throw new InflateException("Could not inflate " + name, e); 108 } catch (InvocationTargetException e) { 109 throw new InflateException("Could not inflate " + name, e); 110 } 111 } 112 return null; 113 } 114 115 @Override onCreateView(View parent, String name, Context context, AttributeSet attrs)116 public View onCreateView(View parent, String name, Context context, AttributeSet attrs) { 117 return onCreateView(name, context, attrs); 118 } 119 } 120 } 121