blob: 755046af1d3e709ed9c3f0c9ee52cbb15c7b314b [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* 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 com.android.systemui.car.statusicon;
import static com.android.systemui.car.statusicon.StatusIconController.PANEL_CONTENT_LAYOUT_NONE;
import android.annotation.ArrayRes;
import android.annotation.ColorInt;
import android.annotation.LayoutRes;
import android.content.Context;
import android.content.res.Resources;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.policy.ConfigurationController;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.inject.Provider;
/**
* A base controller for a view that contains a group of StatusIcons. It creates a button view for
* each icon to display, instantiates {@link StatusIconController} instances associated with those
* icons, and then registers those icons to those controllers.
*/
public abstract class StatusIconGroupContainerController {
private final Context mContext;
private final Resources mResources;
private final CarServiceProvider mCarServiceProvider;
private final BroadcastDispatcher mBroadcastDispatcher;
private final ConfigurationController mConfigurationController;
private final Map<Class<?>, Provider<StatusIconController>> mIconControllerCreators;
private final String mIconTag;
private final String[] mStatusIconControllerNames;
private final Set<StatusIconPanelController> mStatusIconPanelControllers;
private Map<String, View> mStatusIconViewClassMap;
public StatusIconGroupContainerController(
Context context,
@Main Resources resources,
CarServiceProvider carServiceProvider,
BroadcastDispatcher broadcastDispatcher,
ConfigurationController configurationController,
Map<Class<?>, Provider<StatusIconController>> iconControllerCreators) {
mContext = context;
mResources = resources;
mCarServiceProvider = carServiceProvider;
mBroadcastDispatcher = broadcastDispatcher;
mConfigurationController = configurationController;
mIconControllerCreators = iconControllerCreators;
mIconTag = mResources.getString(R.string.qc_icon_tag);
mStatusIconControllerNames = mResources.getStringArray(
getStatusIconControllersStringArray());
mStatusIconViewClassMap = new HashMap<>();
mStatusIconPanelControllers = new HashSet<>();
}
private static <T> T resolve(String className, Map<Class<?>, Provider<T>> creators) {
try {
Class<?> clazz = Class.forName(className);
Provider<T> provider = creators.get(clazz);
return provider == null ? null : provider.get();
} catch (ClassNotFoundException e) {
return null;
}
}
/**
* Returns the layout res id to use as the button view that contains the StatusIcon.
*/
@LayoutRes
public int getButtonViewLayout() {
return R.layout.default_status_icon;
}
/**
* See {@link #addIconViews(ViewGroup, boolean)}
*/
public void addIconViews(ViewGroup containerViewGroup) {
addIconViews(containerViewGroup, /* shouldAttachPanel= */ true);
}
/**
* Adds Quick Control entry points to the provided container ViewGroup. Also attaches
* the Quick Control panel if it's specified and allowed.
*/
public void addIconViews(ViewGroup containerViewGroup, boolean shouldAttachPanel) {
LayoutInflater li = LayoutInflater.from(mContext);
@ColorInt int iconNotHighlightedColor = mContext.getColor(
R.color.status_icon_not_highlighted_color);
for (String clsName : mStatusIconControllerNames) {
StatusIconController statusIconController = getStatusIconControllerByName(clsName);
View entryPointView = li.inflate(getButtonViewLayout(),
containerViewGroup, /* attachToRoot= */ false);
entryPointView.setId(statusIconController.getId());
ImageView statusIconView = entryPointView.findViewWithTag(mIconTag);
statusIconController.registerIconView(statusIconView);
statusIconView.setColorFilter(iconNotHighlightedColor);
if (shouldAttachPanel
&& statusIconController.getPanelContentLayout() != PANEL_CONTENT_LAYOUT_NONE) {
StatusIconPanelController panelController = new StatusIconPanelController(mContext,
mCarServiceProvider, mBroadcastDispatcher, mConfigurationController);
panelController.attachPanel(entryPointView,
statusIconController.getPanelContentLayout(),
statusIconController.getPanelWidth());
mStatusIconPanelControllers.add(panelController);
}
containerViewGroup.addView(entryPointView);
mStatusIconViewClassMap.put(clsName, entryPointView);
}
}
/** Gets the class name of the selected View. */
public String getClassNameOfSelectedView() {
for (String clsName : mStatusIconViewClassMap.keySet()) {
View statusIconView = mStatusIconViewClassMap.get(clsName);
if (statusIconView.isSelected()) {
return clsName;
}
}
return null;
}
/** Gets the View corresponding to the given class name. */
public View getViewFromClassName(String clsName) {
return mStatusIconViewClassMap.getOrDefault(clsName, null);
}
/** Resets the cached Views. */
public void resetCache() {
for (StatusIconPanelController panelController : mStatusIconPanelControllers) {
panelController.destroyPanel();
}
mStatusIconPanelControllers.clear();
mStatusIconViewClassMap.clear();
}
@ArrayRes
protected abstract int getStatusIconControllersStringArray();
private StatusIconController getStatusIconControllerByName(String className) {
try {
StatusIconController statusIconController = resolveStatusIconController(className);
if (statusIconController == null) {
Constructor constructor = Class.forName(className).getConstructor(Context.class);
statusIconController = (StatusIconController) constructor.newInstance(this);
}
return statusIconController;
} catch (ClassNotFoundException
| NoSuchMethodException
| IllegalAccessException
| InstantiationException
| InvocationTargetException ex) {
throw new RuntimeException(ex);
}
}
private StatusIconController resolveStatusIconController(String className) {
return resolve(className, mIconControllerCreators);
}
@VisibleForTesting
public void setStatusIconViewClassMap(Map<String, View> statusIconViewClassMap) {
mStatusIconViewClassMap = statusIconViewClassMap;
}
}