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
17package com.android.gallery3d.ui;
18
19import android.content.Context;
20import android.graphics.Rect;
21import android.view.LayoutInflater;
22import android.view.View;
23import android.view.View.MeasureSpec;
24import android.view.ViewGroup;
25import android.view.ViewTreeObserver;
26import android.view.ViewTreeObserver.OnGlobalLayoutListener;
27import android.widget.AdapterView;
28import android.widget.AdapterView.OnItemClickListener;
29import android.widget.BaseAdapter;
30import android.widget.ListView;
31import android.widget.PopupWindow;
32import android.widget.TextView;
33
34import com.android.gallery3d.R;
35
36import java.util.ArrayList;
37
38public class PopupList {
39
40    public static interface OnPopupItemClickListener {
41        public boolean onPopupItemClick(int itemId);
42    }
43
44    public static class Item {
45        public final int id;
46        public String title;
47
48        public Item(int id, String title) {
49            this.id = id;
50            this.title = title;
51        }
52
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
69    public PopupList(Context context, View anchorView) {
70        mContext = context;
71        mAnchorView = anchorView;
72    }
73
74    public void setOnPopupItemClickListener(OnPopupItemClickListener listener) {
75        mOnPopupItemClickListener = listener;
76    }
77
78    public void addItem(int id, String title) {
79        mItems.add(new Item(id, title));
80    }
81
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
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
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
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
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
181        public int getCount() {
182            return mItems.size();
183        }
184
185        @Override
186        public Object getItem(int position) {
187            return mItems.get(position);
188        }
189
190        @Override
191        public long getItemId(int position) {
192            return mItems.get(position).id;
193        }
194
195        @Override
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