302 lines
11 KiB
Java
302 lines
11 KiB
Java
/*
|
|
* Copyright 2011 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.example.android.actionbarcompat;
|
|
|
|
import org.xmlpull.v1.XmlPullParser;
|
|
import org.xmlpull.v1.XmlPullParserException;
|
|
|
|
import android.app.Activity;
|
|
import android.content.Context;
|
|
import android.content.res.XmlResourceParser;
|
|
import android.os.Bundle;
|
|
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.LinearLayout;
|
|
import android.widget.ProgressBar;
|
|
import android.widget.TextView;
|
|
|
|
import java.io.IOException;
|
|
import java.util.HashSet;
|
|
import java.util.Set;
|
|
|
|
/**
|
|
* A class that implements the action bar pattern for pre-Honeycomb devices.
|
|
*/
|
|
public class ActionBarHelperBase extends ActionBarHelper {
|
|
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";
|
|
|
|
protected Set<Integer> mActionItemIds = new HashSet<Integer>();
|
|
|
|
protected ActionBarHelperBase(Activity activity) {
|
|
super(activity);
|
|
}
|
|
|
|
/**{@inheritDoc}*/
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
mActivity.requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
|
|
}
|
|
|
|
/**{@inheritDoc}*/
|
|
@Override
|
|
public void onPostCreate(Bundle savedInstanceState) {
|
|
mActivity.getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
|
|
R.layout.actionbar_compat);
|
|
setupActionBar();
|
|
|
|
SimpleMenu menu = new SimpleMenu(mActivity);
|
|
mActivity.onCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, menu);
|
|
mActivity.onPrepareOptionsMenu(menu);
|
|
for (int i = 0; i < menu.size(); i++) {
|
|
MenuItem item = menu.getItem(i);
|
|
if (mActionItemIds.contains(item.getItemId())) {
|
|
addActionItemCompatFromMenuItem(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets up the compatibility action bar with the given title.
|
|
*/
|
|
private void setupActionBar() {
|
|
final ViewGroup actionBarCompat = getActionBarCompat();
|
|
if (actionBarCompat == null) {
|
|
return;
|
|
}
|
|
|
|
LinearLayout.LayoutParams springLayoutParams = new LinearLayout.LayoutParams(
|
|
0, ViewGroup.LayoutParams.FILL_PARENT);
|
|
springLayoutParams.weight = 1;
|
|
|
|
// Add Home button
|
|
SimpleMenu tempMenu = new SimpleMenu(mActivity);
|
|
SimpleMenuItem homeItem = new SimpleMenuItem(
|
|
tempMenu, android.R.id.home, 0, mActivity.getString(R.string.app_name));
|
|
homeItem.setIcon(R.drawable.ic_home);
|
|
addActionItemCompatFromMenuItem(homeItem);
|
|
|
|
// Add title text
|
|
TextView titleText = new TextView(mActivity, null, R.attr.actionbarCompatTitleStyle);
|
|
titleText.setLayoutParams(springLayoutParams);
|
|
titleText.setText(mActivity.getTitle());
|
|
actionBarCompat.addView(titleText);
|
|
}
|
|
|
|
/**{@inheritDoc}*/
|
|
@Override
|
|
public void setRefreshActionItemState(boolean refreshing) {
|
|
View refreshButton = mActivity.findViewById(R.id.actionbar_compat_item_refresh);
|
|
View refreshIndicator = mActivity.findViewById(
|
|
R.id.actionbar_compat_item_refresh_progress);
|
|
|
|
if (refreshButton != null) {
|
|
refreshButton.setVisibility(refreshing ? View.GONE : View.VISIBLE);
|
|
}
|
|
if (refreshIndicator != null) {
|
|
refreshIndicator.setVisibility(refreshing ? View.VISIBLE : View.GONE);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Action bar helper code to be run in {@link Activity#onCreateOptionsMenu(android.view.Menu)}.
|
|
*
|
|
* NOTE: This code will mark on-screen menu items as invisible.
|
|
*/
|
|
@Override
|
|
public boolean onCreateOptionsMenu(Menu menu) {
|
|
// Hides on-screen action items from the options menu.
|
|
for (Integer id : mActionItemIds) {
|
|
menu.findItem(id).setVisible(false);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**{@inheritDoc}*/
|
|
@Override
|
|
protected void onTitleChanged(CharSequence title, int color) {
|
|
TextView titleView = (TextView) mActivity.findViewById(R.id.actionbar_compat_title);
|
|
if (titleView != null) {
|
|
titleView.setText(title);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a {@link android.view.MenuInflater} that can read action bar metadata on
|
|
* pre-Honeycomb devices.
|
|
*/
|
|
public MenuInflater getMenuInflater(MenuInflater superMenuInflater) {
|
|
return new WrappedMenuInflater(mActivity, superMenuInflater);
|
|
}
|
|
|
|
/**
|
|
* Returns the {@link android.view.ViewGroup} for the action bar on phones (compatibility action
|
|
* bar). Can return null, and will return null on Honeycomb.
|
|
*/
|
|
private ViewGroup getActionBarCompat() {
|
|
return (ViewGroup) mActivity.findViewById(R.id.actionbar_compat);
|
|
}
|
|
|
|
/**
|
|
* 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.example.android.actionbarcompat.ActionBarHelperBase#setRefreshActionItemState(boolean)}.
|
|
*/
|
|
private View addActionItemCompatFromMenuItem(final MenuItem item) {
|
|
final int itemId = item.getItemId();
|
|
|
|
final ViewGroup actionBar = getActionBarCompat();
|
|
if (actionBar == null) {
|
|
return null;
|
|
}
|
|
|
|
// Create the button
|
|
ImageButton actionButton = new ImageButton(mActivity, null,
|
|
itemId == android.R.id.home
|
|
? R.attr.actionbarCompatItemHomeStyle
|
|
: R.attr.actionbarCompatItemStyle);
|
|
actionButton.setLayoutParams(new ViewGroup.LayoutParams(
|
|
(int) mActivity.getResources().getDimension(
|
|
itemId == android.R.id.home
|
|
? R.dimen.actionbar_compat_button_home_width
|
|
: R.dimen.actionbar_compat_button_width),
|
|
ViewGroup.LayoutParams.FILL_PARENT));
|
|
if (itemId == R.id.menu_refresh) {
|
|
actionButton.setId(R.id.actionbar_compat_item_refresh);
|
|
}
|
|
actionButton.setImageDrawable(item.getIcon());
|
|
actionButton.setScaleType(ImageView.ScaleType.CENTER);
|
|
actionButton.setContentDescription(item.getTitle());
|
|
actionButton.setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View view) {
|
|
mActivity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item);
|
|
}
|
|
});
|
|
|
|
actionBar.addView(actionButton);
|
|
|
|
if (item.getItemId() == R.id.menu_refresh) {
|
|
// Refresh buttons should be stateful, and allow for indeterminate progress indicators,
|
|
// so add those.
|
|
ProgressBar indicator = new ProgressBar(mActivity, null,
|
|
R.attr.actionbarCompatProgressIndicatorStyle);
|
|
|
|
final int buttonWidth = mActivity.getResources().getDimensionPixelSize(
|
|
R.dimen.actionbar_compat_button_width);
|
|
final int buttonHeight = mActivity.getResources().getDimensionPixelSize(
|
|
R.dimen.actionbar_compat_height);
|
|
final int progressIndicatorWidth = buttonWidth / 2;
|
|
|
|
LinearLayout.LayoutParams indicatorLayoutParams = new LinearLayout.LayoutParams(
|
|
progressIndicatorWidth, progressIndicatorWidth);
|
|
indicatorLayoutParams.setMargins(
|
|
(buttonWidth - progressIndicatorWidth) / 2,
|
|
(buttonHeight - progressIndicatorWidth) / 2,
|
|
(buttonWidth - progressIndicatorWidth) / 2,
|
|
0);
|
|
indicator.setLayoutParams(indicatorLayoutParams);
|
|
indicator.setVisibility(View.GONE);
|
|
indicator.setId(R.id.actionbar_compat_item_refresh_progress);
|
|
actionBar.addView(indicator);
|
|
}
|
|
|
|
return actionButton;
|
|
}
|
|
|
|
/**
|
|
* A {@link android.view.MenuInflater} that reads action bar metadata.
|
|
*/
|
|
private class WrappedMenuInflater extends MenuInflater {
|
|
MenuInflater mInflater;
|
|
|
|
public WrappedMenuInflater(Context context, MenuInflater inflater) {
|
|
super(context);
|
|
mInflater = inflater;
|
|
}
|
|
|
|
@Override
|
|
public void inflate(int menuRes, Menu menu) {
|
|
loadActionBarMetadata(menuRes);
|
|
mInflater.inflate(menuRes, menu);
|
|
}
|
|
|
|
/**
|
|
* 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 loadActionBarMetadata(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);
|
|
if (showAsAction == MenuItem.SHOW_AS_ACTION_ALWAYS ||
|
|
showAsAction == MenuItem.SHOW_AS_ACTION_IF_ROOM) {
|
|
mActionItemIds.add(itemId);
|
|
}
|
|
break;
|
|
|
|
case XmlPullParser.END_DOCUMENT:
|
|
eof = true;
|
|
break;
|
|
}
|
|
|
|
eventType = parser.next();
|
|
}
|
|
} catch (XmlPullParserException e) {
|
|
throw new InflateException("Error inflating menu XML", e);
|
|
} catch (IOException e) {
|
|
throw new InflateException("Error inflating menu XML", e);
|
|
} finally {
|
|
if (parser != null) {
|
|
parser.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|