1 /*
2  * Copyright (C) 2012 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.gallery3d.ui;
18 
19 import android.content.Context;
20 import android.graphics.Rect;
21 import android.view.LayoutInflater;
22 import android.view.View;
23 import android.view.View.MeasureSpec;
24 import android.view.ViewGroup;
25 import android.view.ViewTreeObserver;
26 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
27 import android.widget.AdapterView;
28 import android.widget.AdapterView.OnItemClickListener;
29 import android.widget.BaseAdapter;
30 import android.widget.ListView;
31 import android.widget.PopupWindow;
32 import android.widget.TextView;
33 
34 import com.android.gallery3d.R;
35 
36 import java.util.ArrayList;
37 
38 public class PopupList {
39 
40     public static interface OnPopupItemClickListener {
onPopupItemClick(int itemId)41         public boolean onPopupItemClick(int itemId);
42     }
43 
44     public static class Item {
45         public final int id;
46         public String title;
47 
Item(int id, String title)48         public Item(int id, String title) {
49             this.id = id;
50             this.title = title;
51         }
52 
setTitle(String title)53         public void setTitle(String title) {
54             this.title = title;
55         }
56     }
57 
58     private final Context mContext;
59     private final View mAnchorView;
60     private final ArrayList<Item> mItems = new ArrayList<Item>();
61     private PopupWindow mPopupWindow;
62     private ListView mContentList;
63     private OnPopupItemClickListener mOnPopupItemClickListener;
64     private int mPopupOffsetX;
65     private int mPopupOffsetY;
66     private int mPopupWidth;
67     private int mPopupHeight;
68 
PopupList(Context context, View anchorView)69     public PopupList(Context context, View anchorView) {
70         mContext = context;
71         mAnchorView = anchorView;
72     }
73 
setOnPopupItemClickListener(OnPopupItemClickListener listener)74     public void setOnPopupItemClickListener(OnPopupItemClickListener listener) {
75         mOnPopupItemClickListener = listener;
76     }
77 
addItem(int id, String title)78     public void addItem(int id, String title) {
79         mItems.add(new Item(id, title));
80     }
81 
clearItems()82     public void clearItems() {
83         mItems.clear();
84     }
85 
86     private final PopupWindow.OnDismissListener mOnDismissListener =
87             new PopupWindow.OnDismissListener() {
88         @SuppressWarnings("deprecation")
89         @Override
90         public void onDismiss() {
91             if (mPopupWindow == null) return;
92             mPopupWindow = null;
93             ViewTreeObserver observer = mAnchorView.getViewTreeObserver();
94             if (observer.isAlive()) {
95                 // We used the deprecated function for backward compatibility
96                 // The new "removeOnGlobalLayoutListener" is introduced in API level 16
97                 observer.removeGlobalOnLayoutListener(mOnGLobalLayoutListener);
98             }
99         }
100     };
101 
102     private final OnItemClickListener mOnItemClickListener =
103             new OnItemClickListener() {
104         @Override
105         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
106             if (mPopupWindow == null) return;
107             mPopupWindow.dismiss();
108             if (mOnPopupItemClickListener != null) {
109                 mOnPopupItemClickListener.onPopupItemClick((int) id);
110             }
111         }
112     };
113 
114     private final OnGlobalLayoutListener mOnGLobalLayoutListener =
115             new OnGlobalLayoutListener() {
116         @Override
117         public void onGlobalLayout() {
118             if (mPopupWindow == null) return;
119             updatePopupLayoutParams();
120             // Need to update the position of the popup window
121             mPopupWindow.update(mAnchorView,
122                     mPopupOffsetX, mPopupOffsetY, mPopupWidth, mPopupHeight);
123         }
124     };
125 
show()126     public void show() {
127         if (mPopupWindow != null) return;
128         mAnchorView.getViewTreeObserver()
129                 .addOnGlobalLayoutListener(mOnGLobalLayoutListener);
130         mPopupWindow = createPopupWindow();
131         updatePopupLayoutParams();
132         mPopupWindow.setWidth(mPopupWidth);
133         mPopupWindow.setHeight(mPopupHeight);
134         mPopupWindow.showAsDropDown(mAnchorView, mPopupOffsetX, mPopupOffsetY);
135     }
136 
updatePopupLayoutParams()137     private void updatePopupLayoutParams() {
138         ListView content = mContentList;
139         PopupWindow popup = mPopupWindow;
140 
141         Rect p = new Rect();
142         popup.getBackground().getPadding(p);
143 
144         int maxHeight = mPopupWindow.getMaxAvailableHeight(mAnchorView) - p.top - p.bottom;
145         mContentList.measure(
146                 MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
147                 MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST));
148         mPopupWidth = content.getMeasuredWidth() + p.top + p.bottom;
149         mPopupHeight = Math.min(maxHeight, content.getMeasuredHeight() + p.left + p.right);
150         mPopupOffsetX = -p.left;
151         mPopupOffsetY = -p.top;
152     }
153 
createPopupWindow()154     private PopupWindow createPopupWindow() {
155         PopupWindow popup = new PopupWindow(mContext);
156         popup.setOnDismissListener(mOnDismissListener);
157 
158         popup.setBackgroundDrawable(mContext.getResources().getDrawable(
159                 R.drawable.menu_dropdown_panel_holo_dark));
160 
161         mContentList = new ListView(mContext, null,
162                 android.R.attr.dropDownListViewStyle);
163         mContentList.setAdapter(new ItemDataAdapter());
164         mContentList.setOnItemClickListener(mOnItemClickListener);
165         popup.setContentView(mContentList);
166         popup.setFocusable(true);
167         popup.setOutsideTouchable(true);
168 
169         return popup;
170     }
171 
findItem(int id)172     public Item findItem(int id) {
173         for (Item item : mItems) {
174             if (item.id == id) return item;
175         }
176         return null;
177     }
178 
179     private class ItemDataAdapter extends BaseAdapter {
180         @Override
getCount()181         public int getCount() {
182             return mItems.size();
183         }
184 
185         @Override
getItem(int position)186         public Object getItem(int position) {
187             return mItems.get(position);
188         }
189 
190         @Override
getItemId(int position)191         public long getItemId(int position) {
192             return mItems.get(position).id;
193         }
194 
195         @Override
getView(int position, View convertView, ViewGroup parent)196         public View getView(int position, View convertView, ViewGroup parent) {
197             if (convertView == null) {
198                 convertView = LayoutInflater.from(mContext)
199                         .inflate(R.layout.popup_list_item, null);
200             }
201             TextView text = (TextView) convertView.findViewById(android.R.id.text1);
202             text.setText(mItems.get(position).title);
203             return convertView;
204         }
205     }
206 }
207