1b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg/* 2b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * Copyright (C) 2015 The Android Open Source Project 3b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * 4b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * Licensed under the Apache License, Version 2.0 (the "License"); 5b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * you may not use this file except in compliance with the License. 6b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * You may obtain a copy of the License at 7b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * 8b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * http://www.apache.org/licenses/LICENSE-2.0 9b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * 10b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * Unless required by applicable law or agreed to in writing, software 11b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * distributed under the License is distributed on an "AS IS" BASIS, 12b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * See the License for the specific language governing permissions and 14b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * limitations under the License. 15b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg */ 16b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 17b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasbergpackage com.android.internal.view.menu; 18b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 1928a8468995c71ba3fbba12557d143e7599db38d8Alan Viveretteimport android.annotation.NonNull; 2028a8468995c71ba3fbba12557d143e7599db38d8Alan Viveretteimport android.annotation.Nullable; 21b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasbergimport android.content.Context; 2291098574f90277128415e9593cce1e495cc51465Alan Viveretteimport android.graphics.Rect; 23ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasbergimport android.view.MenuItem; 24b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasbergimport android.view.View; 25b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasbergimport android.view.View.MeasureSpec; 26b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasbergimport android.view.ViewGroup; 27ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasbergimport android.widget.AdapterView; 28b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasbergimport android.widget.FrameLayout; 29ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasbergimport android.widget.HeaderViewListAdapter; 30b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasbergimport android.widget.ListAdapter; 31b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasbergimport android.widget.PopupWindow; 32b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 33b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg/** 34b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * Base class for a menu popup abstraction - i.e., some type of menu, housed in a popup window 35b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * environment. 36b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * 37b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * @hide 38b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg */ 39ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasbergpublic abstract class MenuPopup implements ShowableListMenu, MenuPresenter, 40ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg AdapterView.OnItemClickListener { 4191098574f90277128415e9593cce1e495cc51465Alan Viverette private Rect mEpicenterBounds; 42b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 43b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg public abstract void setForceShowIcon(boolean forceShow); 44b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 45b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg /** 468e12f8df076d38853e0fedde7ed79e2e8689d59eOren Blasberg * Adds the given menu to the popup, if it is capable of displaying submenus within itself. 478e12f8df076d38853e0fedde7ed79e2e8689d59eOren Blasberg * If menu is the first menu shown, it won't be displayed until show() is called. 488e12f8df076d38853e0fedde7ed79e2e8689d59eOren Blasberg * If the popup was already showing, adding a submenu via this method will cause that new 498e12f8df076d38853e0fedde7ed79e2e8689d59eOren Blasberg * submenu to be shown immediately (that is, if this MenuPopup implementation is capable of 508e12f8df076d38853e0fedde7ed79e2e8689d59eOren Blasberg * showing its own submenus). 51b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * 52b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * @param menu 53b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg */ 54b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg public abstract void addMenu(MenuBuilder menu); 55b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 56b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg public abstract void setGravity(int dropDownGravity); 57b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 58b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg public abstract void setAnchorView(View anchor); 59b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 60ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg public abstract void setHorizontalOffset(int x); 61ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg 62ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg public abstract void setVerticalOffset(int y); 63ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg 64ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg /** 6591098574f90277128415e9593cce1e495cc51465Alan Viverette * Specifies the anchor-relative bounds of the popup's transition 6691098574f90277128415e9593cce1e495cc51465Alan Viverette * epicenter. 6791098574f90277128415e9593cce1e495cc51465Alan Viverette * 6891098574f90277128415e9593cce1e495cc51465Alan Viverette * @param bounds anchor-relative bounds 6991098574f90277128415e9593cce1e495cc51465Alan Viverette */ 7091098574f90277128415e9593cce1e495cc51465Alan Viverette public void setEpicenterBounds(Rect bounds) { 7191098574f90277128415e9593cce1e495cc51465Alan Viverette mEpicenterBounds = bounds; 7291098574f90277128415e9593cce1e495cc51465Alan Viverette } 7391098574f90277128415e9593cce1e495cc51465Alan Viverette 7491098574f90277128415e9593cce1e495cc51465Alan Viverette /** 7591098574f90277128415e9593cce1e495cc51465Alan Viverette * @return anchor-relative bounds of the popup's transition epicenter 7691098574f90277128415e9593cce1e495cc51465Alan Viverette */ 7791098574f90277128415e9593cce1e495cc51465Alan Viverette public Rect getEpicenterBounds() { 7891098574f90277128415e9593cce1e495cc51465Alan Viverette return mEpicenterBounds; 7991098574f90277128415e9593cce1e495cc51465Alan Viverette } 8091098574f90277128415e9593cce1e495cc51465Alan Viverette 8191098574f90277128415e9593cce1e495cc51465Alan Viverette /** 82ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg * Set whether a title entry should be shown in the popup menu (if a title exists for the 83ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg * menu). 84ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg * 85ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg * @param showTitle 86ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg */ 87ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg public abstract void setShowTitle(boolean showTitle); 88ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg 89b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg /** 90b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * Set a listener to receive a callback when the popup is dismissed. 91b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * 92b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * @param listener Listener that will be notified when the popup is dismissed. 93b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg */ 94b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg public abstract void setOnDismissListener(PopupWindow.OnDismissListener listener); 95b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 96b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg @Override 9728a8468995c71ba3fbba12557d143e7599db38d8Alan Viverette public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) { 98b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg // Don't need to do anything; we added as a presenter in the constructor. 99b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg } 100b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 101b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg @Override 102b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg public MenuView getMenuView(ViewGroup root) { 103b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg throw new UnsupportedOperationException("MenuPopups manage their own views"); 104b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg } 105b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 106b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg @Override 107b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) { 108b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg return false; 109b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg } 110b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 111b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg @Override 112b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) { 113b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg return false; 114b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg } 115b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 116b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg @Override 117b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg public int getId() { 118b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg return 0; 119b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg } 120b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 121ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg @Override 122ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 123ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg ListAdapter outerAdapter = (ListAdapter) parent.getAdapter(); 124ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg MenuAdapter wrappedAdapter = toMenuAdapter(outerAdapter); 125ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg 126ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg // Use the position from the outer adapter so that if a header view was added, we don't get 127ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg // an off-by-1 error in position. 128ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg wrappedAdapter.mAdapterMenu.performItemAction((MenuItem) outerAdapter.getItem(position), 0); 129ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg } 130ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg 131b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg /** 132b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * Measures the width of the given menu view. 133b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * 134b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * @param view The view to measure. 135b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg * @return The width. 136b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg */ 137b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg protected static int measureIndividualMenuWidth(ListAdapter adapter, ViewGroup parent, 138b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg Context context, int maxAllowedWidth) { 139b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg // Menus don't tend to be long, so this is more sane than it looks. 140b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg int maxWidth = 0; 141b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg View itemView = null; 142b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg int itemType = 0; 143b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 144b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 145b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 146b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg final int count = adapter.getCount(); 147b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg for (int i = 0; i < count; i++) { 148b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg final int positionType = adapter.getItemViewType(i); 149b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg if (positionType != itemType) { 150b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg itemType = positionType; 151b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg itemView = null; 152b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg } 153b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 154b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg if (parent == null) { 155b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg parent = new FrameLayout(context); 156b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg } 157b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 158b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg itemView = adapter.getView(i, itemView, parent); 159b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg itemView.measure(widthMeasureSpec, heightMeasureSpec); 160b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 161b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg final int itemWidth = itemView.getMeasuredWidth(); 162b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg if (itemWidth >= maxAllowedWidth) { 163b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg return maxAllowedWidth; 164b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg } else if (itemWidth > maxWidth) { 165b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg maxWidth = itemWidth; 166b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg } 167b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg } 168b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg 169b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg return maxWidth; 170b23976efdd6ffe42cb3b8fe6650fc77bd9a161e8Oren Blasberg } 171ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg 172ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg /** 173ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg * Converts the given ListAdapter originating from a menu, to a MenuAdapter, accounting for 174ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg * the possibility of the parameter adapter actually wrapping the MenuAdapter. (That could 175ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg * happen if a header view was added on the menu.) 176ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg * 177ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg * @param adapter 178ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg * @return 179ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg */ 180ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg protected static MenuAdapter toMenuAdapter(ListAdapter adapter) { 181ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg if (adapter instanceof HeaderViewListAdapter) { 182ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg return (MenuAdapter) ((HeaderViewListAdapter) adapter).getWrappedAdapter(); 183ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg } 184ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg return (MenuAdapter) adapter; 185ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg } 186ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg 187ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg /** 188ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg * Returns whether icon spacing needs to be preserved for the given menu, based on whether any 189ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg * of its items contains an icon. 1903610d06239e72bb51e4150889864d2b2c18347d5Oren Blasberg * 1913610d06239e72bb51e4150889864d2b2c18347d5Oren Blasberg * NOTE: This should only be used for non-overflow-only menus, because this method does not 1923610d06239e72bb51e4150889864d2b2c18347d5Oren Blasberg * take into account whether the menu items are being shown as part of the popup or or being 1933610d06239e72bb51e4150889864d2b2c18347d5Oren Blasberg * shown as actions in the action bar. 1943610d06239e72bb51e4150889864d2b2c18347d5Oren Blasberg * 195ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg * @param menu 196ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg * @return Whether to preserve icon spacing. 197ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg */ 198ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg protected static boolean shouldPreserveIconSpacing(MenuBuilder menu) { 199ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg boolean preserveIconSpacing = false; 200ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg final int count = menu.size(); 201ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg 202ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg for (int i = 0; i < count; i++) { 203ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg MenuItem childItem = menu.getItem(i); 204ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg if (childItem.isVisible() && childItem.getIcon() != null) { 205ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg preserveIconSpacing = true; 206ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg break; 207ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg } 208ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg } 209ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg 210ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg return preserveIconSpacing; 211ddf6b8130f62c82241544bef19bcee4ef3171a82Oren Blasberg } 212ed3912692f0ba8a647d795462e20fcdb67adbacbOren Blasberg} 213