From 44ef42f215d68ade8b63d18fede944c244a2a1dd Mon Sep 17 00:00:00 2001 From: Owen Lin Date: Wed, 11 Jul 2012 11:20:00 +0800 Subject: [PATCH] Make CustomMenu compatible with API level 10. bug: 6802855 Change-Id: I230c91bd9744935a181881131dcd2275ed89d819 --- .../menu_dropdown_panel_holo_dark.9.png | Bin 0 -> 922 bytes .../menu_dropdown_panel_holo_dark.9.png | Bin 0 -> 651 bytes .../menu_dropdown_panel_holo_dark.9.png | Bin 0 -> 1362 bytes .../selection.xml => layout/popup_list_item.xml} | 17 +- res/values/ids.xml | 1 + .../android/gallery3d/ui/ActionModeHandler.java | 50 +++--- src/com/android/gallery3d/ui/CustomMenu.java | 89 ---------- src/com/android/gallery3d/ui/PopupList.java | 188 +++++++++++++++++++++ src/com/android/gallery3d/ui/SelectionMenu.java | 61 +++++++ 9 files changed, 285 insertions(+), 121 deletions(-) create mode 100644 res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png create mode 100644 res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png create mode 100644 res/drawable-xhdpi/menu_dropdown_panel_holo_dark.9.png rename res/{menu/selection.xml => layout/popup_list_item.xml} (54%) delete mode 100644 src/com/android/gallery3d/ui/CustomMenu.java create mode 100644 src/com/android/gallery3d/ui/PopupList.java create mode 100644 src/com/android/gallery3d/ui/SelectionMenu.java diff --git a/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png b/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..4d3d208578c61662986fdc16bd15c69759b48d6a GIT binary patch literal 922 zcmV;L17-Y)P)!ytdud6iMT7O&4bD*mP3eKws)UN7D2k#e z%DbYt@4NEYnkjlINEK7=*RV3zwml#Px9r!q%}Y$QM*NqHEZ-wscn^ zf4p9=Kg#ZZAKY%YZvc!aCbL}F6eGxtBSzy=smEUmc6C{?q1YCQrid~5o$!73+BeU$Ee{DI^Yo4#-o87 zao*xiE9Z<+s}ttlWw19HGlEA1nW09+*~|#}a;CkeJh%bU1g9CP5h0^O2}4Hs%y=Lc z5q!OY8j*^uk~rBBK?ljmh#jL84Ev;rDo>_H#K|6e%Mo=CgLzw$rI$Y4Z-kUy6U47Z zMI2w^tmuV~pH%tJq!^(yWY-hbFl2;G2g)+VPqud2Sicc+jL>MvBTKK;HbN#jlrS<8 zl+;FqdPULzJ~Kh_!?j8>!xs^*nQAm$#290~ue;BBnY1w&wMw4#m(pwEDZd_oY1{Ux z>$>N)H(eWD*FCpw`-IsDKF28-6~1bz!JGs-W6Z&R1n>#KR{&q8us99Q}8ID#(NJr3oa@N-D4Rc$qhA--bT2} z_Wpf@Z`4749}#V+fwWJz^oyZKO1~J&exY-1*Kg?D$hu!fixvAiNfpmG;mo&f5BSEA wlE;@gYed_N;JFm#Y)Zw{1W}kQU9GkF3xsHEK4Myn7XSbN07*qoM6N<$g18=|djJ3c literal 0 HcmV?d00001 diff --git a/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png b/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..460ec46eb0786706610e21ac9097de489cedfc33 GIT binary patch literal 651 zcmV;60(AX}P)!1&^00004b3#c}2nYxW zdZ_-Wf*5)VugS&t+23J}V*z%DOHb#W|`Z#l>;cJ*L_P;jGoKD8nX4Z`xH*Q>s zTvTl`b;%gqS1znaOc|u@tz3t7=|UK<9Hr>BJ|D1%4AOYzE>c>YASL1(e+Y^`_iG?7 z1UL~EK(|`0e*W#*UXt~C{TfUweyI5sSBLVgO?u)p&e9+4(C=i^T1GuQJ|j^LdEE0 zfZFjzm@Nd117_`XxKDqSoJXh_wG-}tW_yHE!!B|TSvyio<6k9eTgoG9O0aTdZJ81x zmbul8Z%fpkT#Wc{ND1L@No&VX#iPVF7hx`c0JdkE;3e2%ZBQYi%Oe#dj=&z+_I>|? zOJi$dCv)FoZJG3n&>Qp|;vSo*JOkf=A5uR{`;uV-QwsX>Ho!a31HXV*se5TxFFA=4 zo=3!%#5;D2+DO|6R;c8b^-B2j{s4XhZw!t1m&l3O!HmBwHn=!)kb6yF?kI1MVX*Vu z<6hz)DH{^YBPWDzO$|0isCW3@P>L98oO;C$E5=4jGEPjLS?XZ=13IvJLaC?O;nLn? z=e?6_T^b`&$N3sK+o1N3^-DyB&=+_N>geY)_rHdJwBJ%s{^4(_WBZ5MLQM53U4RfX laXn(LVYMe-Njr@(d;;;gyUim^Wn%yU002ovPDHLkV1m`SB-{W1 literal 0 HcmV?d00001 diff --git a/res/drawable-xhdpi/menu_dropdown_panel_holo_dark.9.png b/res/drawable-xhdpi/menu_dropdown_panel_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e2aff72f483ce4cc6ccddf17331249fa612d2a83 GIT binary patch literal 1362 zcmV-Y1+DstP)?8OR-p?Vt(<)KXNk*dJ1<_`!jRpab6RMK;Rk47fDU#NEX#7yk4(~&Fr}L7DZp)K} zK)DDZgb+dqA%qY@2q7)3S*px^wsY!a9l?~jW2$HoDfOAoDc4?$q=mJH$Q@HesW|pH zEqI5t5pt#=^`ykNb$bDA+g_!6r>E#0Ebxb)V~E)@66{HSu%o+0#^7QK=<56_<*0g z4?VWXMFRkJB8s~XX6q}?LEeWW=Ef--P!X+fp` zQ#hbt=1@CWv@?Vrj0n$wG-wfB>s2&!$QdDJ0ulZgw-cuRiR{Y>^Hj3K6cvDZyr8vA z8lxp5*y$r9!v6G_XAF7`2PhmT)XW;J_(x39;8bKfgMu`e! zU+jWXwIOOF0-q>8C*JQsY~7_bBCuA z|Ap1-2&vJi9g(t&*dI@qVtrbEm_q)8uxlUymW^N&DQrSTF2REQdw9B(B*Fk-L?96w zfdFVX0=tCgq*<4>5rKwy4p!?>V+1b~mqyqhPm^M8N}pNlWK7Aa(;L|rtB1{dT%;u; z=)dm(?jeLfE6zhUB!2hW01y9MdY)1v=ujhBx3b+Xm&>Pd9KV)clx)K|j$bdA%O^}( zPFj=H`w_B~E-2}`eIdjBd_I2}hT(GvVW{|jkQIawhG7^!pU>wnc#H_%SRreOrJP6k z#f!~#`~_1^!^gPqw^)9R`+vop3DslHn(o!PiI0dTt@|45Za=)m1`%IwEW{fV$LVaF zE9RVsAMaWMjZlg;f(R_4iy{7r`=s=`3SdP<&^M)TPHqgUw5?z25;3$902*NlyMU*S zpa+j$RH$BIEX`7~H`b|A%pl=Pj|o!QHv-L&MvImjnCmfv9y@5Gq|A_|G$L4MNvqdg zg%(@J38}FG4N!(%uhEggMhM*%9HY#I^l zO-Wr$p$z~$ref=30GgqO)XJdORd}!BEq>NeB8p9{v^kJo2|NxCQwf^HCpGf6X;Wp4 zg!hgmb$FtdtQ>ASMriqL^@|$FBEhNWjw@zMktp~+Gzo9nO1w>OhBUKE#}ER(1L)vD UI+1b(O8@`>07*qoM6N<$f~tseq5uE@ literal 0 HcmV?d00001 diff --git a/res/menu/selection.xml b/res/layout/popup_list_item.xml similarity index 54% rename from res/menu/selection.xml rename to res/layout/popup_list_item.xml index 18839e4d2..4dbc610d9 100644 --- a/res/menu/selection.xml +++ b/res/layout/popup_list_item.xml @@ -1,5 +1,5 @@ - - - - + + diff --git a/res/values/ids.xml b/res/values/ids.xml index b6fda4771..7babba067 100644 --- a/res/values/ids.xml +++ b/res/values/ids.xml @@ -18,4 +18,5 @@ --> + diff --git a/src/com/android/gallery3d/ui/ActionModeHandler.java b/src/com/android/gallery3d/ui/ActionModeHandler.java index 190b2b8c6..80d2500d4 100644 --- a/src/com/android/gallery3d/ui/ActionModeHandler.java +++ b/src/com/android/gallery3d/ui/ActionModeHandler.java @@ -22,7 +22,6 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.nfc.NfcAdapter; -import android.os.Build; import android.os.Handler; import android.view.ActionMode; import android.view.LayoutInflater; @@ -31,7 +30,6 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.Button; -import android.widget.PopupMenu.OnMenuItemClickListener; import android.widget.ShareActionProvider; import android.widget.ShareActionProvider.OnShareTargetSelectedListener; @@ -43,7 +41,6 @@ import com.android.gallery3d.common.Utils; import com.android.gallery3d.data.DataManager; import com.android.gallery3d.data.MediaObject; import com.android.gallery3d.data.Path; -import com.android.gallery3d.ui.CustomMenu.DropDownMenu; import com.android.gallery3d.ui.MenuExecutor.ProgressListener; import com.android.gallery3d.util.Future; import com.android.gallery3d.util.GalleryUtils; @@ -52,7 +49,8 @@ import com.android.gallery3d.util.ThreadPool.JobContext; import java.util.ArrayList; -public class ActionModeHandler implements ActionMode.Callback { +public class ActionModeHandler implements + ActionMode.Callback, PopupList.OnPopupItemClickListener { private static final String TAG = "ActionModeHandler"; private static final int SUPPORT_MULTIPLE_MASK = MediaObject.SUPPORT_DELETE | MediaObject.SUPPORT_ROTATE | MediaObject.SUPPORT_SHARE @@ -67,7 +65,7 @@ public class ActionModeHandler implements ActionMode.Callback { private final SelectionManager mSelectionManager; private final NfcAdapter mNfcAdapter; private Menu mMenu; - private DropDownMenu mSelectionMenu; + private SelectionMenu mSelectionMenu; private ActionModeListener mListener; private Future mMenuTask; private final Handler mMainHandler; @@ -85,20 +83,13 @@ public class ActionModeHandler implements ActionMode.Callback { public ActionMode startActionMode() { Activity a = (Activity) mActivity; final ActionMode actionMode = a.startActionMode(this); - CustomMenu customMenu = new CustomMenu(a); View customView = LayoutInflater.from(a).inflate( R.layout.action_mode, null); actionMode.setCustomView(customView); - mSelectionMenu = customMenu.addDropDownMenu( - (Button) customView.findViewById(R.id.selection_menu), - R.menu.selection); + mSelectionMenu = new SelectionMenu(a, + (Button) customView.findViewById(R.id.selection_menu), this); updateSelectionMenu(); - customMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - return onActionItemClicked(actionMode, item); - } - }); + return actionMode; } @@ -137,14 +128,25 @@ public class ActionModeHandler implements ActionMode.Callback { R.plurals.delete_selection, mSelectionManager.getSelectedCount()); } mMenuExecutor.onMenuClicked(item, confirmMsg, listener); - if (action == R.id.action_select_all) { + } finally { + root.unlockRenderThread(); + } + return true; + } + + @Override + public boolean onPopupItemClick(int itemId) { + GLRoot root = mActivity.getGLRoot(); + root.lockRenderThread(); + try { + if (itemId == R.id.action_select_all) { updateSupportedOperation(); - updateSelectionMenu(); + mMenuExecutor.onMenuClicked(itemId, null, false, true); } + return true; } finally { root.unlockRenderThread(); } - return true; } private void updateSelectionMenu() { @@ -153,18 +155,10 @@ public class ActionModeHandler implements ActionMode.Callback { String format = mActivity.getResources().getQuantityString( R.plurals.number_of_items_selected, count); setTitle(String.format(format, count)); + // For clients who call SelectionManager.selectAll() directly, we need to ensure the // menu status is consistent with selection manager. - MenuItem item = mSelectionMenu.findItem(R.id.action_select_all); - if (item != null) { - if (mSelectionManager.inSelectAllMode()) { - item.setChecked(true); - item.setTitle(R.string.deselect_all); - } else { - item.setChecked(false); - item.setTitle(R.string.select_all); - } - } + mSelectionMenu.updateSelectAllMode(mSelectionManager.inSelectAllMode()); } public boolean onCreateActionMode(ActionMode mode, Menu menu) { diff --git a/src/com/android/gallery3d/ui/CustomMenu.java b/src/com/android/gallery3d/ui/CustomMenu.java deleted file mode 100644 index 15b3dc2c2..000000000 --- a/src/com/android/gallery3d/ui/CustomMenu.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.ui; - -import android.content.Context; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.PopupMenu; -import android.widget.PopupMenu.OnMenuItemClickListener; - -import java.util.ArrayList; - -public class CustomMenu implements OnMenuItemClickListener { - @SuppressWarnings("unused") - private static final String TAG = "FilterMenu"; - - public static class DropDownMenu { - private Button mButton; - private PopupMenu mPopupMenu; - private Menu mMenu; - - public DropDownMenu(Context context, Button button, int menuId, - OnMenuItemClickListener listener) { - mButton = button; - mPopupMenu = new PopupMenu(context, mButton); - mMenu = mPopupMenu.getMenu(); - mPopupMenu.getMenuInflater().inflate(menuId, mMenu); - mPopupMenu.setOnMenuItemClickListener(listener); - mButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mPopupMenu.show(); - } - }); - } - - public MenuItem findItem(int id) { - return mMenu.findItem(id); - } - - public void setTitle(CharSequence title) { - mButton.setText(title); - } - } - - private Context mContext; - private ArrayList mMenus; - private OnMenuItemClickListener mListener; - - public CustomMenu(Context context) { - mContext = context; - mMenus = new ArrayList(); - } - - public DropDownMenu addDropDownMenu(Button button, int menuId) { - DropDownMenu menu = new DropDownMenu(mContext, button, menuId, this); - mMenus.add(menu); - return menu; - } - - public void setOnMenuItemClickListener(OnMenuItemClickListener listener) { - mListener = listener; - } - - @Override - public boolean onMenuItemClick(MenuItem item) { - if (mListener != null) { - return mListener.onMenuItemClick(item); - } - return false; - } -} diff --git a/src/com/android/gallery3d/ui/PopupList.java b/src/com/android/gallery3d/ui/PopupList.java new file mode 100644 index 000000000..ee02029c7 --- /dev/null +++ b/src/com/android/gallery3d/ui/PopupList.java @@ -0,0 +1,188 @@ +// Copyright 2012 Google Inc. All Rights Reserved. + +package com.android.gallery3d.ui; + +import android.content.Context; +import android.graphics.Rect; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.MeasureSpec; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.OnGlobalLayoutListener; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.BaseAdapter; +import android.widget.ListView; +import android.widget.PopupWindow; +import android.widget.TextView; + +import com.android.gallery3d.R; +import com.android.gallery3d.common.Utils; + +import java.util.ArrayList; + +public class PopupList { + + public static interface OnPopupItemClickListener { + public boolean onPopupItemClick(int itemId); + } + + public static class Item { + public final int id; + public String title; + + public Item(int id, String title) { + this.id = id; + this.title = title; + } + + public void setTitle(String title) { + this.title = title; + } + } + + private final Context mContext; + private final View mAnchorView; + private final ArrayList mItems = new ArrayList(); + private PopupWindow mPopupWindow; + private ListView mContentList; + private OnPopupItemClickListener mOnPopupItemClickListener; + private int mPopupOffsetX; + private int mPopupOffsetY; + private int mPopupWidth; + private int mPopupHeight; + + public PopupList(Context context, View anchorView) { + mContext = context; + mAnchorView = anchorView; + } + + public void setOnPopupItemClickListener(OnPopupItemClickListener listener) { + mOnPopupItemClickListener = listener; + } + + public void addItem(int id, String title) { + mItems.add(new Item(id, title)); + } + + private final PopupWindow.OnDismissListener mOnDismissListener = + new PopupWindow.OnDismissListener() { + @SuppressWarnings("deprecation") + @Override + public void onDismiss() { + if (mPopupWindow == null) return; + mPopupWindow = null; + ViewTreeObserver observer = mAnchorView.getViewTreeObserver(); + if (observer.isAlive()) { + // We used the deprecated function for backward compatibility + // The new "removeOnGlobalLayoutListener" is introduced in API level 16 + observer.removeGlobalOnLayoutListener(mOnGLobalLayoutListener); + } + } + }; + + private final OnItemClickListener mOnItemClickListener = + new OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + Utils.debug("onItemClick: %s, %s", position, id); + if (mPopupWindow == null) return; + mPopupWindow.dismiss(); + if (mOnPopupItemClickListener != null) { + mOnPopupItemClickListener.onPopupItemClick((int) id); + } + } + }; + + private final OnGlobalLayoutListener mOnGLobalLayoutListener = + new OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + if (mPopupWindow == null) return; + updatePopupLayoutParams(); + // Need to update the position of the popup window + mPopupWindow.update(mAnchorView, + mPopupOffsetX, mPopupOffsetY, mPopupWidth, mPopupHeight); + } + }; + + public void show() { + if (mPopupWindow != null) return; + mAnchorView.getViewTreeObserver() + .addOnGlobalLayoutListener(mOnGLobalLayoutListener); + mPopupWindow = createPopupWindow(); + updatePopupLayoutParams(); + mPopupWindow.setWidth(mPopupWidth); + mPopupWindow.setHeight(mPopupHeight); + mPopupWindow.showAsDropDown(mAnchorView, mPopupOffsetX, mPopupOffsetY); + } + + private void updatePopupLayoutParams() { + ListView content = mContentList; + PopupWindow popup = mPopupWindow; + + Rect p = new Rect(); + popup.getBackground().getPadding(p); + + int maxHeight = mPopupWindow.getMaxAvailableHeight(mAnchorView) - p.top - p.bottom; + mContentList.measure( + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), + MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST)); + mPopupWidth = content.getMeasuredWidth() + p.top + p.bottom; + mPopupHeight = Math.min(maxHeight, content.getMeasuredHeight() + p.left + p.right); + mPopupOffsetX = -p.left; + mPopupOffsetY = -p.top; + } + + private PopupWindow createPopupWindow() { + PopupWindow popup = new PopupWindow(); + popup.setOnDismissListener(mOnDismissListener); + + popup.setBackgroundDrawable(mContext.getResources().getDrawable( + R.drawable.menu_dropdown_panel_holo_dark)); + mContentList = new ListView(mContext); + mContentList.setAdapter(new ItemDataAdapter()); + mContentList.setOnItemClickListener(mOnItemClickListener); + popup.setContentView(mContentList); + popup.setFocusable(true); + popup.setOutsideTouchable(true); + + return popup; + } + + public Item findItem(int id) { + for (Item item : mItems) { + if (item.id == id) return item; + } + return null; + } + + private class ItemDataAdapter extends BaseAdapter { + @Override + public int getCount() { + return mItems.size(); + } + + @Override + public Object getItem(int position) { + return mItems.get(position); + } + + @Override + public long getItemId(int position) { + return mItems.get(position).id; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = LayoutInflater.from(mContext) + .inflate(R.layout.popup_list_item, null); + } + TextView text = (TextView) convertView.findViewById(android.R.id.text1); + text.setText(mItems.get(position).title); + return convertView; + } + } +} diff --git a/src/com/android/gallery3d/ui/SelectionMenu.java b/src/com/android/gallery3d/ui/SelectionMenu.java new file mode 100644 index 000000000..5b0828328 --- /dev/null +++ b/src/com/android/gallery3d/ui/SelectionMenu.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.ui; + +import android.content.Context; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; + +import com.android.gallery3d.R; +import com.android.gallery3d.ui.PopupList.OnPopupItemClickListener; + +public class SelectionMenu implements OnClickListener { + @SuppressWarnings("unused") + private static final String TAG = "SelectionMenu"; + + private final Context mContext; + private final Button mButton; + private final PopupList mPopupList; + + public SelectionMenu(Context context, Button button, OnPopupItemClickListener listener) { + mContext = context; + mButton = button; + mPopupList = new PopupList(context, mButton); + mPopupList.addItem(R.id.action_select_all, + context.getString(R.string.select_all)); + mPopupList.setOnPopupItemClickListener(listener); + mButton.setOnClickListener(this); + } + + @Override + public void onClick(View v) { + mPopupList.show(); + } + + public void updateSelectAllMode(boolean inSelectAllMode) { + PopupList.Item item = mPopupList.findItem(R.id.action_select_all); + if (item != null) { + item.setTitle(mContext.getString( + inSelectAllMode ? R.string.deselect_all : R.string.select_all)); + } + } + + public void setTitle(CharSequence title) { + mButton.setText(title); + } +} -- 2.11.0