/******************************************************************************* * Copyright 2012 momock.com * * 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.momock.holo.internal.actionbar; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.XmlResourceParser; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.view.Gravity; import android.view.InflateException; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import android.widget.TextView; import android.widget.Toast; import com.momock.ext.holo.R; import com.momock.holo.app.ActionBar; import com.momock.holo.internal.menu.MenuImpl; import com.momock.holo.internal.menu.MenuItemImpl; import com.momock.holo.widget.PopupMenu; import com.momock.holo.widget.PopupMenu.OnMenuItemClickListener; public class ActionBarCompatBase extends ActionBarCompat implements ActionBar { private static final String MENU_RES_NAMESPACE = "http://schemas.android.com/apk/res/android"; private static final String MENU_ATTR_ID = "id"; private static final String MENU_ATTR_SHOW_AS_ACTION = "showAsAction"; private final Activity mActivity; private View mActionBarView, mCustomView, mHomeAsUpIndicator; private ImageView mIconView; private TextView mTitleView, mSubtitleView; private ViewGroup mHomeView, mTitleContainer, mCustomViewContainer, mActionMenuView, mActionModeContainer; private final Menu mRealMenu, mActionBarMenu; private boolean mProgressBarIndeterminateEnabled = false; private boolean mActionModeShowing; public ActionBarCompatBase(final Activity activity) { mActivity = activity; mActionBarMenu = new MenuImpl(activity); mRealMenu = new MenuImpl(mActivity); } public void createActionBarMenu() { mActivity.onCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, mRealMenu); mActivity.onPrepareOptionsMenu(mRealMenu); } @Override public View getCustomView() { return mCustomView; } @Override public int getHeight() { if (mActionBarView != null) { mActionBarView.getHeight(); } return 0; } /** * Returns a {@link android.view.MenuInflater} that can read action bar * metadata on pre-Honeycomb devices. */ @Override public MenuInflater getMenuInflater(final MenuInflater superMenuInflater) { return new SupportMenuInflater(mActivity, superMenuInflater); } @Override public CharSequence getSubtitle() { if (mSubtitleView == null) return null; return mSubtitleView.getText(); } @Override public CharSequence getTitle() { if (mTitleView == null) return null; return mTitleView.getText(); } @SuppressWarnings("deprecation") @Override public void setBackgroundDrawable(final Drawable d) { if (mActionBarView != null) { mActionBarView.setBackgroundDrawable(d); } } @Override public void setCustomView(final int resId) { if (mActivity == null) return; setCustomView(mActivity.getLayoutInflater().inflate(resId, null)); } @Override public void setCustomView(final View view) { if (mCustomViewContainer == null) return; mCustomViewContainer.removeAllViews(); mCustomViewContainer.addView(view); mCustomView = view; } @Override public void setDisplayHomeAsUpEnabled(final boolean showHomeAsUp) { if (mHomeAsUpIndicator == null) return; mHomeAsUpIndicator.setVisibility(showHomeAsUp ? View.VISIBLE : View.INVISIBLE); } @Override public void setDisplayShowCustomEnabled(final boolean enabled) { if (mCustomViewContainer == null) return; mCustomViewContainer.setVisibility(enabled ? View.VISIBLE : View.GONE); } @Override public void setDisplayShowHomeEnabled(final boolean showHome) { if (mHomeView == null) return; mHomeView.setVisibility(showHome ? View.VISIBLE : View.GONE); } @Override public void setDisplayShowTitleEnabled(final boolean enabled) { if (mTitleContainer == null) return; mTitleContainer.setVisibility(enabled ? View.VISIBLE : View.GONE); } @Override public void setSubtitle(final CharSequence subtitle) { if (mSubtitleView == null) return; mSubtitleView.setText(subtitle); mSubtitleView.setVisibility(subtitle != null ? View.VISIBLE : View.GONE); } @Override public void setSubtitle(final int resId) { setSubtitle(mActivity.getString(resId)); } @Override public void setTitle(final CharSequence title) { if (mTitleView == null) return; mTitleView.setText(title); } @Override public void setTitle(final int resId) { setTitle(mActivity.getString(resId)); } /** * Adds an action button to the compatibility action bar, using menu * information from a {@link android.view.MenuItem}. If the menu item ID is * <code>menu_refresh</code>, the menu item's state can be changed to show a * loading spinner using * {@link com.android.actionbarcompat.ActionBarHelperBase#setRefreshActionItemState(boolean)} * . */ private View addActionItemCompatFromMenuItem(final MenuItem item) { if (mActionMenuView == null || item == null) return null; // Create the button final ImageButton actionButton = new ImageButton(mActivity, null, R.attr.actionBarItemStyle); // actionButton.setVisibility(item.isVisible() ? View.VISIBLE : // View.GONE); actionButton.setLayoutParams(new ViewGroup.LayoutParams((int) mActivity.getResources().getDimension( R.dimen.actionbar_button_width), ViewGroup.LayoutParams.MATCH_PARENT)); actionButton.setId(item.getItemId()); actionButton.setImageDrawable(item.getIcon()); actionButton.setScaleType(ScaleType.CENTER); actionButton.setContentDescription(item.getTitle()); actionButton.setVisibility(item.isVisible() ? View.VISIBLE : View.GONE); actionButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View view) { if (!item.isEnabled()) return; if (item.hasSubMenu()) { final PopupMenu popup = PopupMenu.getInstance(mActivity, view); popup.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override public boolean onMenuItemClick(final MenuItem item) { return mActivity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item); } }); popup.setMenu(item.getSubMenu()); popup.show(); } mActivity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item); } }); actionButton.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(final View v) { if (item.getItemId() == android.R.id.home) return false; final Toast t = Toast.makeText(mActivity, item.getTitle(), Toast.LENGTH_SHORT); final int[] screenPos = new int[2]; final Rect displayFrame = new Rect(); v.getLocationOnScreen(screenPos); v.getWindowVisibleDisplayFrame(displayFrame); final int width = v.getWidth(); final int height = v.getHeight(); final int midy = screenPos[1] + height / 2; final int screenWidth = mActivity.getResources().getDisplayMetrics().widthPixels; if (midy < displayFrame.height()) { // Show along the top; follow action buttons t.setGravity(Gravity.TOP | Gravity.RIGHT, screenWidth - screenPos[0] - width / 2, height); } else { // Show along the bottom center t.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height); } t.show(); return true; } }); mActionMenuView.addView(actionButton); return actionButton; } private void clearMenuItems() { if (mActionMenuView == null) return; mActionMenuView.removeAllViews(); } private void setHomeButton() { // Add Home button final MenuItem homeItem = MenuItemImpl.createItem(mActivity, android.R.id.home); final PackageManager pm = mActivity.getPackageManager(); try { if (mIconView != null) { mIconView.setImageDrawable(pm.getActivityIcon(mActivity.getComponentName())); } } catch (final NameNotFoundException e) { // This should not happen. } if (mHomeView != null) { mHomeView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View view) { mActivity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, homeItem); } }); } } public void hideInRealMenu(final Menu menu) { if (menu instanceof MenuImpl || menu == null) return; for (int i = 0; i < menu.size(); i++) { final MenuItem realItem = menu.getItem(i); if (realItem == null) { continue; } if (mActionBarMenu.findItem(realItem.getItemId()) != null) { realItem.setVisible(false); } } } public void invalidateOptionsMenu() { final SupportMenu menu = new SupportMenu(mActivity); mActivity.onPrepareOptionsMenu(menu); clearMenuItems(); for (final MenuItem item : ((MenuImpl) mActionBarMenu).getMenuItems()) { addActionItemCompatFromMenuItem(item); } } public boolean isActionModeShowing() { return mActionModeShowing; } public boolean requestCustomTitleView() { if (mActivity != null) { mActivity.requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); return true; } return false; } public boolean setCustomTitleView() { mActivity.getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.actionbar); mActionBarView = mActivity.findViewById(R.id.actionbar); mActionModeContainer = (ViewGroup) mActivity.findViewById(R.id.action_mode_container); if (mActionBarView == null) return false; mTitleContainer = (ViewGroup) mActionBarView.findViewById(R.id.actionbar_title_view); mTitleView = (TextView) mTitleContainer.findViewById(R.id.actionbar_title); mSubtitleView = (TextView) mTitleContainer.findViewById(R.id.actionbar_subtitle); mHomeView = (ViewGroup) mActionBarView.findViewById(R.id.actionbar_home); mIconView = (ImageView) mHomeView.findViewById(R.id.actionbar_icon); mHomeAsUpIndicator = mHomeView.findViewById(R.id.actionbar_home_as_up_indicator); mActionMenuView = (ViewGroup) mActionBarView.findViewById(R.id.actionbar_menu_buttons); mCustomViewContainer = (ViewGroup) mActionBarView.findViewById(R.id.actionbar_custom_view_container); setTitle(mActivity.getTitle()); // Add Home button setHomeButton(); createActionBarMenu(); return true; } public void setProgressBarIndeterminateEnabled(final boolean enabled) { mProgressBarIndeterminateEnabled = enabled; } public void setProgressBarIndeterminateVisibility(final boolean visible) { if (mProgressBarIndeterminateEnabled) { mActionBarView.findViewById(R.id.actionbar_progress_indeterminate).setVisibility( visible ? View.VISIBLE : View.GONE); } } View startActionMode() { mActionModeShowing = true; mActionModeContainer.setVisibility(View.VISIBLE); return mActionModeContainer; } void stopActionMode() { mActionModeContainer.setVisibility(View.GONE); final TextView title_view = (TextView) mActionModeContainer.findViewById(R.id.action_mode_title); final TextView subtitle_view = (TextView) mActionModeContainer.findViewById(R.id.action_mode_subtitle); final MenuBar menu_bar = (MenuBar) mActionModeContainer.findViewById(R.id.action_mode_menu); title_view.setText(null); subtitle_view.setText(null); subtitle_view.setVisibility(View.GONE); menu_bar.getMenu().clear(); mActionModeShowing = false; } class SupportMenu extends MenuImpl { private final Context context; SupportMenu(final Context context) { super(context); this.context = context; } @Override public MenuItem findItem(final int id) { for (final MenuItem item : ((MenuImpl) mRealMenu).getMenuItems()) { if (item.getItemId() == id) return new SupportMenuItem(context, id); } return null; } } /** * A {@link android.view.MenuInflater} that reads action bar metadata. */ class SupportMenuInflater extends MenuInflater { final MenuInflater mInflater; SupportMenuInflater(final Context context, final MenuInflater inflater) { super(context); mInflater = inflater; } @Override public void inflate(final int menuRes, final Menu menu) { mInflater.inflate(menuRes, menu); // if (!(menu instanceof MenuImpl)) { mActionBarMenu.clear(); mInflater.inflate(menuRes, mActionBarMenu); removeDuplicateMenuInActionBar(menu, menuRes); // } } /** * Loads action bar metadata from a menu resource, storing a list of * menu item IDs that should be shown on-screen (i.e. those with * showAsAction set to always or ifRoom). * * @param menuResId */ private void removeDuplicateMenuInActionBar(final Menu menu, final int menuResId) { XmlResourceParser parser = null; try { parser = mActivity.getResources().getXml(menuResId); int eventType = parser.getEventType(); int itemId; int showAsAction; boolean eof = false; while (!eof) { switch (eventType) { case XmlPullParser.START_TAG: if (!parser.getName().equals("item")) { break; } itemId = parser.getAttributeResourceValue(MENU_RES_NAMESPACE, MENU_ATTR_ID, 0); if (itemId == 0) { break; } showAsAction = parser .getAttributeIntValue(MENU_RES_NAMESPACE, MENU_ATTR_SHOW_AS_ACTION, -1); final MenuItem item = menu.findItem(itemId); if (item == null) { break; } final boolean isShowAsAction = showAsAction == MenuItem.SHOW_AS_ACTION_ALWAYS || showAsAction == MenuItem.SHOW_AS_ACTION_IF_ROOM || showAsAction == MenuItem.SHOW_AS_ACTION_WITH_TEXT; if (!isShowAsAction && mActionBarMenu instanceof MenuImpl) { final List<MenuItem> items = ((MenuImpl) mActionBarMenu).getMenuItems(); final List<MenuItem> items_to_remove = new ArrayList<MenuItem>(); for (final MenuItem actionItem : items) { if (item.getItemId() == actionItem.getItemId()) { items_to_remove.add(actionItem); } } items.removeAll(items_to_remove); } item.setVisible(!isShowAsAction); break; case XmlPullParser.END_DOCUMENT: eof = true; break; } eventType = parser.next(); } } catch (final XmlPullParserException e) { throw new InflateException("Error inflating menu XML", e); } catch (final IOException e) { throw new InflateException("Error inflating menu XML", e); } finally { if (parser != null) { parser.close(); } } invalidateOptionsMenu(); } } class SupportMenuItem extends MenuItemImpl { private final int itemId; SupportMenuItem(final Context context, final int itemId) { super(context); this.itemId = itemId; } @Override public MenuItem setEnabled(final boolean enabled) { if (mActionBarMenu == null || mRealMenu == null) return this; final MenuItem item = mActionBarMenu.findItem(itemId); final MenuItem realItem = mRealMenu.findItem(itemId); if (item != null) { item.setEnabled(enabled); final View view = mActionMenuView.findViewById(itemId); if (view != null) { view.setEnabled(enabled); } } if (realItem != null) { realItem.setEnabled(enabled); } return this; } @Override public MenuItem setIcon(final int iconRes) { if (mActionBarMenu == null || mRealMenu == null) return this; final MenuItem item = mActionBarMenu.findItem(itemId); final MenuItem realItem = mRealMenu.findItem(itemId); if (item != null) { item.setIcon(iconRes); } if (realItem != null) { realItem.setIcon(iconRes); } return this; } @Override public MenuItem setTitle(final int titleRes) { if (mActionBarMenu == null || mRealMenu == null) return this; final MenuItem item = mActionBarMenu.findItem(itemId); final MenuItem realItem = mRealMenu.findItem(itemId); if (item != null) { item.setTitle(titleRes); } if (realItem != null) { realItem.setTitle(titleRes); } return this; } @Override public MenuItem setVisible(final boolean visible) { if (mActionBarMenu == null || mRealMenu == null || mActionMenuView == null) return this; final MenuItem item = mActionBarMenu.findItem(itemId); final MenuItem realItem = mRealMenu.findItem(itemId); if (item != null) { item.setVisible(visible); final View view = mActionMenuView.findViewById(itemId); if (view != null) { view.setVisibility(visible ? View.VISIBLE : View.GONE); } if (realItem != null) { realItem.setVisible(false); } return this; } if (realItem != null) { realItem.setVisible(visible); } return this; } } }