1 /* 2 * Copyright (C) 2020 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 package com.android.systemui.globalactions; 17 18 import android.annotation.NonNull; 19 import android.annotation.Nullable; 20 import android.content.Context; 21 import android.content.res.Resources; 22 import android.util.LayoutDirection; 23 import android.view.View; 24 import android.view.View.MeasureSpec; 25 import android.widget.AdapterView; 26 import android.widget.ListAdapter; 27 import android.widget.ListPopupWindow; 28 import android.widget.ListView; 29 30 import com.android.systemui.R; 31 32 /** 33 * Customized widget for use in the GlobalActionsDialog. Ensures common positioning and user 34 * interactions. 35 * 36 * It should be created with a {@link Context} with the right theme 37 */ 38 public class GlobalActionsPopupMenu extends ListPopupWindow { 39 private Context mContext; 40 private boolean mIsDropDownMode; 41 private int mMenuVerticalPadding = 0; 42 private int mGlobalActionsSidePadding = 0; 43 private int mMaximumWidthThresholdDp = 800; 44 private ListAdapter mAdapter; 45 private AdapterView.OnItemLongClickListener mOnItemLongClickListener; 46 GlobalActionsPopupMenu(@onNull Context context, boolean isDropDownMode)47 public GlobalActionsPopupMenu(@NonNull Context context, boolean isDropDownMode) { 48 super(context); 49 mContext = context; 50 Resources res = mContext.getResources(); 51 setBackgroundDrawable( 52 res.getDrawable(R.drawable.global_actions_popup_bg, context.getTheme())); 53 mIsDropDownMode = isDropDownMode; 54 55 setInputMethodMode(INPUT_METHOD_NOT_NEEDED); 56 setModal(true); 57 58 mGlobalActionsSidePadding = res.getDimensionPixelSize(R.dimen.global_actions_side_margin); 59 if (!isDropDownMode) { 60 mMenuVerticalPadding = res.getDimensionPixelSize(R.dimen.control_menu_vertical_padding); 61 } 62 } 63 64 /** 65 * Set the listadapter used to populate this menu. 66 */ setAdapter(@ullable ListAdapter adapter)67 public void setAdapter(@Nullable ListAdapter adapter) { 68 mAdapter = adapter; 69 super.setAdapter(adapter); 70 } 71 72 /** 73 * Show the dialog. 74 */ show()75 public void show() { 76 // need to call show() first in order to construct the listView 77 super.show(); 78 if (mOnItemLongClickListener != null) { 79 getListView().setOnItemLongClickListener(mOnItemLongClickListener); 80 } 81 82 ListView listView = getListView(); 83 Resources res = mContext.getResources(); 84 85 setVerticalOffset(-getAnchorView().getHeight() / 2); 86 87 if (mIsDropDownMode) { 88 // use a divider 89 listView.setDividerHeight(res.getDimensionPixelSize(R.dimen.control_list_divider)); 90 listView.setDivider(res.getDrawable(R.drawable.global_actions_list_divider_inset)); 91 } else { 92 if (mAdapter == null) return; 93 94 // width should be between [.5, .9] of screen 95 int parentWidth = res.getSystem().getDisplayMetrics().widthPixels; 96 float parentDensity = res.getSystem().getDisplayMetrics().density; 97 float parentWidthDp = parentWidth / parentDensity; 98 int widthSpec = MeasureSpec.makeMeasureSpec( 99 (int) (parentWidth * 0.9), MeasureSpec.AT_MOST); 100 int maxWidth = 0; 101 for (int i = 0; i < mAdapter.getCount(); i++) { 102 View child = mAdapter.getView(i, null, listView); 103 child.measure(widthSpec, MeasureSpec.UNSPECIFIED); 104 int w = child.getMeasuredWidth(); 105 maxWidth = Math.max(w, maxWidth); 106 } 107 108 int width = maxWidth; 109 if (parentWidthDp < mMaximumWidthThresholdDp) { 110 width = Math.max(maxWidth, (int) (parentWidth * 0.5)); 111 } 112 listView.setPadding(0, mMenuVerticalPadding, 0, mMenuVerticalPadding); 113 setWidth(width); 114 if (getAnchorView().getLayoutDirection() == LayoutDirection.LTR) { 115 setHorizontalOffset(getAnchorView().getWidth() - mGlobalActionsSidePadding - width); 116 } else { 117 setHorizontalOffset(mGlobalActionsSidePadding); 118 } 119 } 120 121 super.show(); 122 } 123 setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener)124 public void setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener) { 125 mOnItemLongClickListener = listener; 126 } 127 } 128