1 /* 2 * Copyright (C) 2021 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.car.statusicon; 18 19 import static com.android.systemui.car.statusicon.StatusIconController.PANEL_CONTENT_LAYOUT_NONE; 20 21 import android.annotation.ArrayRes; 22 import android.annotation.ColorInt; 23 import android.annotation.LayoutRes; 24 import android.content.Context; 25 import android.content.res.Resources; 26 import android.view.LayoutInflater; 27 import android.view.View; 28 import android.view.ViewGroup; 29 import android.widget.ImageView; 30 31 import com.android.systemui.R; 32 import com.android.systemui.broadcast.BroadcastDispatcher; 33 import com.android.systemui.car.CarServiceProvider; 34 import com.android.systemui.dagger.qualifiers.Main; 35 import com.android.systemui.statusbar.policy.ConfigurationController; 36 37 import java.lang.reflect.Constructor; 38 import java.lang.reflect.InvocationTargetException; 39 import java.util.Map; 40 41 import javax.inject.Provider; 42 43 /** 44 * A base controller for a view that contains a group of StatusIcons. It creates a button view for 45 * each icon to display, instantiates {@link StatusIconController} instances associated with those 46 * icons, and then registers those icons to those controllers. 47 */ 48 public abstract class StatusIconGroupContainerController { 49 private final Context mContext; 50 private final Resources mResources; 51 private final CarServiceProvider mCarServiceProvider; 52 private final BroadcastDispatcher mBroadcastDispatcher; 53 private final ConfigurationController mConfigurationController; 54 private final Map<Class<?>, Provider<StatusIconController>> mIconControllerCreators; 55 private final String mIconTag; 56 private final @ColorInt int mIconNotHighlightedColor; 57 private final String[] mStatusIconControllerNames; 58 StatusIconGroupContainerController( Context context, @Main Resources resources, CarServiceProvider carServiceProvider, BroadcastDispatcher broadcastDispatcher, ConfigurationController configurationController, Map<Class<?>, Provider<StatusIconController>> iconControllerCreators)59 public StatusIconGroupContainerController( 60 Context context, 61 @Main Resources resources, 62 CarServiceProvider carServiceProvider, 63 BroadcastDispatcher broadcastDispatcher, 64 ConfigurationController configurationController, 65 Map<Class<?>, Provider<StatusIconController>> iconControllerCreators) { 66 mContext = context; 67 mResources = resources; 68 mCarServiceProvider = carServiceProvider; 69 mBroadcastDispatcher = broadcastDispatcher; 70 mConfigurationController = configurationController; 71 mIconControllerCreators = iconControllerCreators; 72 mIconTag = mResources.getString(R.string.qc_icon_tag); 73 mIconNotHighlightedColor = mContext.getColor(R.color.status_icon_not_highlighted_color); 74 mStatusIconControllerNames = mResources.getStringArray( 75 getStatusIconControllersStringArray()); 76 } 77 resolve(String className, Map<Class<?>, Provider<T>> creators)78 private static <T> T resolve(String className, Map<Class<?>, Provider<T>> creators) { 79 try { 80 Class<?> clazz = Class.forName(className); 81 Provider<T> provider = creators.get(clazz); 82 return provider == null ? null : provider.get(); 83 } catch (ClassNotFoundException e) { 84 return null; 85 } 86 } 87 88 /** 89 * Returns the layout res id to use as the button view that contains the StatusIcon. 90 */ 91 @LayoutRes getButtonViewLayout()92 public int getButtonViewLayout() { 93 return R.layout.default_status_icon; 94 } 95 96 /** 97 * See {@link #addIconViews(ViewGroup, boolean)} 98 */ addIconViews(ViewGroup containerViewGroup)99 public void addIconViews(ViewGroup containerViewGroup) { 100 addIconViews(containerViewGroup, /* shouldAttachPanel= */ true); 101 } 102 103 /** 104 * Adds Quick Control entry points to the provided container ViewGroup. Also attaches 105 * the Quick Control panel if it's specified and allowed. 106 */ addIconViews(ViewGroup containerViewGroup, boolean shouldAttachPanel)107 public void addIconViews(ViewGroup containerViewGroup, boolean shouldAttachPanel) { 108 LayoutInflater li = LayoutInflater.from(mContext); 109 110 for (String clsName : mStatusIconControllerNames) { 111 StatusIconController statusIconController = getStatusIconControllerByName(clsName); 112 View entryPointView = li.inflate(getButtonViewLayout(), 113 containerViewGroup, /* attachToRoot= */ false); 114 115 ImageView statusIconView = entryPointView.findViewWithTag(mIconTag); 116 statusIconController.registerIconView(statusIconView); 117 statusIconView.setColorFilter(mIconNotHighlightedColor); 118 119 if (shouldAttachPanel 120 && statusIconController.getPanelContentLayout() != PANEL_CONTENT_LAYOUT_NONE) { 121 StatusIconPanelController panelController = new StatusIconPanelController(mContext, 122 mCarServiceProvider, mBroadcastDispatcher, mConfigurationController); 123 panelController.attachPanel(entryPointView, 124 statusIconController.getPanelContentLayout(), 125 statusIconController.getPanelWidth()); 126 } 127 containerViewGroup.addView(entryPointView); 128 } 129 } 130 131 @ArrayRes getStatusIconControllersStringArray()132 protected abstract int getStatusIconControllersStringArray(); 133 getStatusIconControllerByName(String className)134 private StatusIconController getStatusIconControllerByName(String className) { 135 try { 136 StatusIconController statusIconController = resolveStatusIconController(className); 137 if (statusIconController == null) { 138 Constructor constructor = Class.forName(className).getConstructor(Context.class); 139 statusIconController = (StatusIconController) constructor.newInstance(this); 140 } 141 142 return statusIconController; 143 } catch (ClassNotFoundException 144 | NoSuchMethodException 145 | IllegalAccessException 146 | InstantiationException 147 | InvocationTargetException ex) { 148 throw new RuntimeException(ex); 149 } 150 } 151 resolveStatusIconController(String className)152 private StatusIconController resolveStatusIconController(String className) { 153 return resolve(className, mIconControllerCreators); 154 } 155 } 156