1 /* 2 * Copyright (C) 2023 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.chassis.car.ui.plugin.toolbar; 18 19 import static com.android.car.ui.utils.CarUiUtils.requireViewByRefId; 20 21 import android.text.TextUtils; 22 import android.view.View; 23 import android.view.ViewGroup; 24 import android.widget.ImageView; 25 import android.widget.Switch; 26 import android.widget.TextView; 27 28 import androidx.annotation.LayoutRes; 29 import androidx.asynclayoutinflater.view.AsyncLayoutInflater; 30 31 import com.android.car.ui.toolbar.MenuItem; 32 import com.android.car.ui.uxr.DrawableStateView; 33 34 import com.chassis.car.ui.plugin.R; 35 36 import java.util.function.Consumer; 37 38 class MenuItemRenderer implements MenuItem.Listener { 39 40 private static final int[] RESTRICTED_STATE = new int[]{R.attr.state_ux_restricted}; 41 42 private final int mMenuItemIconSize; 43 44 private boolean mToolbarIsSearching; 45 46 private final MenuItem mMenuItem; 47 private final ViewGroup mParentView; 48 private View mView; 49 private View mIconContainer; 50 private ImageView mIconView; 51 private Switch mSwitch; 52 private TextView mTextView; 53 private TextView mTextWithIconView; 54 private boolean mIndividualClickListeners; 55 MenuItemRenderer(MenuItem item, ViewGroup parentView)56 MenuItemRenderer(MenuItem item, ViewGroup parentView) { 57 mMenuItem = item; 58 mParentView = parentView; 59 mMenuItem.setListener(this); 60 61 mMenuItemIconSize = parentView.getContext().getResources() 62 .getDimensionPixelSize(R.dimen.car_ui_toolbar_menu_item_icon_size); 63 } 64 setToolbarIsSearching(boolean searching)65 void setToolbarIsSearching(boolean searching) { 66 if (searching != mToolbarIsSearching) { 67 mToolbarIsSearching = searching; 68 69 if (mMenuItem.isSearch()) { 70 updateView(); 71 } 72 } 73 } 74 75 @Override onMenuItemChanged(MenuItem changedItem)76 public void onMenuItemChanged(MenuItem changedItem) { 77 updateView(); 78 } 79 createView(Consumer<View> callback)80 void createView(Consumer<View> callback) { 81 AsyncLayoutInflater inflater = new AsyncLayoutInflater(mParentView.getContext()); 82 @LayoutRes int layout = mMenuItem.isPrimary() 83 ? R.layout.car_ui_toolbar_menu_item_primary 84 : R.layout.car_ui_toolbar_menu_item; 85 inflater.inflate(layout, mParentView, (View view, int resid, 86 ViewGroup parent) -> { 87 mView = view; 88 89 mIconContainer = 90 requireViewByRefId(mView, R.id.car_ui_toolbar_menu_item_icon_container); 91 mIconView = requireViewByRefId(mView, R.id.car_ui_toolbar_menu_item_icon); 92 mSwitch = requireViewByRefId(mView, R.id.car_ui_toolbar_menu_item_switch); 93 mTextView = requireViewByRefId(mView, R.id.car_ui_toolbar_menu_item_text); 94 mTextWithIconView = 95 requireViewByRefId(mView, R.id.car_ui_toolbar_menu_item_text_with_icon); 96 mIndividualClickListeners = mView.getContext().getResources() 97 .getBoolean(R.bool.car_ui_toolbar_menuitem_individual_click_listeners); 98 99 updateView(); 100 callback.accept(mView); 101 }); 102 } 103 updateView()104 private void updateView() { 105 if (mView == null) { 106 return; 107 } 108 109 mView.setId(mMenuItem.getId()); 110 111 boolean hasIcon = mMenuItem.getIcon() != null; 112 boolean hasText = !TextUtils.isEmpty(mMenuItem.getTitle()); 113 boolean textAndIcon = mMenuItem.isShowingIconAndTitle(); 114 boolean checkable = mMenuItem.isCheckable(); 115 116 if (!mMenuItem.isVisible() 117 || (mMenuItem.isSearch() && mToolbarIsSearching) 118 || (!checkable && !hasIcon && !hasText)) { 119 mView.setVisibility(View.GONE); 120 return; 121 } 122 mView.setVisibility(View.VISIBLE); 123 mView.setContentDescription(mMenuItem.getTitle()); 124 125 View clickTarget; 126 if (checkable) { 127 mSwitch.setChecked(mMenuItem.isChecked()); 128 clickTarget = mSwitch; 129 } else if (hasText && hasIcon && textAndIcon) { 130 mMenuItem.getIcon().setBounds(0, 0, mMenuItemIconSize, mMenuItemIconSize); 131 mTextWithIconView.setCompoundDrawables(mMenuItem.getIcon(), null, null, null); 132 mTextWithIconView.setText(mMenuItem.getTitle()); 133 clickTarget = mTextWithIconView; 134 } else if (hasIcon) { 135 mIconView.setImageDrawable(mMenuItem.getIcon()); 136 clickTarget = mIconContainer; 137 } else { // hasText will be true 138 mTextView.setText(mMenuItem.getTitle()); 139 clickTarget = mTextView; 140 } 141 142 mIconContainer.setVisibility(clickTarget == mIconContainer ? View.VISIBLE : View.GONE); 143 mTextView.setVisibility(clickTarget == mTextView ? View.VISIBLE : View.GONE); 144 mTextWithIconView.setVisibility(clickTarget == mTextWithIconView 145 ? View.VISIBLE : View.GONE); 146 mSwitch.setVisibility(clickTarget == mSwitch ? View.VISIBLE : View.GONE); 147 148 if (!mIndividualClickListeners) { 149 clickTarget = mView; 150 } 151 152 if (!mMenuItem.isTinted() && hasIcon) { 153 mMenuItem.getIcon().setTintList(null); 154 } 155 156 recursiveSetEnabledAndDrawableState(mView); 157 mView.setActivated(mMenuItem.isActivated()); 158 159 if (mMenuItem.getOnClickListener() != null 160 || mMenuItem.isCheckable() 161 || mMenuItem.isActivatable()) { 162 clickTarget.setOnClickListener(v -> mMenuItem.performClick()); 163 } else if (clickTarget == mView) { 164 mView.setOnClickListener(null); 165 mView.setClickable(false); 166 } 167 } 168 recursiveSetEnabledAndDrawableState(View view)169 private void recursiveSetEnabledAndDrawableState(View view) { 170 view.setEnabled(mMenuItem.isEnabled()); 171 172 int[] drawableState = mMenuItem.isRestricted() ? RESTRICTED_STATE : null; 173 if (view instanceof ImageView) { 174 ((ImageView) view).setImageState(drawableState, true); 175 } else if (view instanceof DrawableStateView) { 176 ((DrawableStateView) view).setExtraDrawableState(drawableState, null); 177 } 178 179 if (view instanceof ViewGroup) { 180 ViewGroup viewGroup = ((ViewGroup) view); 181 for (int i = 0; i < viewGroup.getChildCount(); i++) { 182 recursiveSetEnabledAndDrawableState(viewGroup.getChildAt(i)); 183 } 184 } 185 } 186 } 187