diff options
| -rw-r--r-- | api/current.xml | 573 | ||||
| -rw-r--r-- | core/java/android/app/ActionBar.java | 253 | ||||
| -rw-r--r-- | core/java/android/app/Activity.java | 53 | ||||
| -rw-r--r-- | core/java/android/view/ActionBarView.java | 625 | ||||
| -rw-r--r-- | core/java/android/view/MenuInflater.java | 50 | ||||
| -rw-r--r-- | core/java/android/view/Window.java | 17 | ||||
| -rw-r--r-- | core/java/com/android/internal/app/SplitActionBar.java | 97 | ||||
| -rw-r--r-- | core/java/com/android/internal/view/menu/ActionMenu.java | 263 | ||||
| -rw-r--r-- | core/java/com/android/internal/view/menu/ActionMenuItem.java | 221 | ||||
| -rw-r--r-- | core/res/res/drawable/action_bar_background.xml | 22 | ||||
| -rw-r--r-- | core/res/res/drawable/action_bar_divider.xml | 22 | ||||
| -rw-r--r-- | core/res/res/layout/action_bar_title_item.xml | 22 | ||||
| -rw-r--r-- | core/res/res/layout/screen_action_bar.xml | 40 | ||||
| -rwxr-xr-x | core/res/res/values/attrs.xml | 51 | ||||
| -rw-r--r-- | core/res/res/values/ids.xml | 1 | ||||
| -rw-r--r-- | core/res/res/values/public.xml | 10 | ||||
| -rw-r--r-- | core/res/res/values/styles.xml | 6 | ||||
| -rw-r--r-- | core/res/res/values/themes.xml | 6 | ||||
| -rw-r--r-- | policy/com/android/internal/policy/impl/PhoneWindow.java | 30 |
19 files changed, 2345 insertions, 17 deletions
diff --git a/api/current.xml b/api/current.xml index 671076a..1eaa6f4 100644 --- a/api/current.xml +++ b/api/current.xml @@ -3188,6 +3188,17 @@ visibility="public" > </field> +<field name="customNavigationLayout" + type="int" + transient="false" + volatile="false" + value="16843539" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="cycles" type="int" transient="false" @@ -3452,6 +3463,17 @@ visibility="public" > </field> +<field name="displayOptions" + type="int" + transient="false" + volatile="false" + value="16843537" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="dither" type="int" transient="false" @@ -6884,6 +6906,17 @@ visibility="public" > </field> +<field name="navigationMode" + type="int" + transient="false" + volatile="false" + value="16843536" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="negativeButtonText" type="int" transient="false" @@ -8930,6 +8963,17 @@ visibility="public" > </field> +<field name="subtitle" + type="int" + transient="false" + volatile="false" + value="16843538" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="suggestActionMsg" type="int" transient="false" @@ -10338,6 +10382,28 @@ visibility="public" > </field> +<field name="windowActionBar" + type="int" + transient="false" + volatile="false" + value="16843534" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="windowActionBarStyle" + type="int" + transient="false" + volatile="false" + value="16843535" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="windowAnimationStyle" type="int" transient="false" @@ -14218,6 +14284,17 @@ visibility="public" > </field> +<field name="home" + type="int" + transient="false" + volatile="false" + value="16908353" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="icon" type="int" transient="false" @@ -16388,6 +16465,17 @@ visibility="public" > </field> +<field name="Theme_WithActionBar" + type="int" + transient="false" + volatile="false" + value="16973969" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="Widget" type="int" transient="false" @@ -19210,6 +19298,454 @@ </package> <package name="android.app" > +<class name="ActionBar" + extends="java.lang.Object" + abstract="true" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="ActionBar" + type="android.app.ActionBar" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<method name="getCustomNavigationView" + return="android.view.View" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getDisplayOptions" + return="int" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getNavigationMode" + return="int" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getSubtitle" + return="java.lang.CharSequence" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getTitle" + return="java.lang.CharSequence" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="setBackgroundDrawable" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="d" type="android.graphics.drawable.Drawable"> +</parameter> +</method> +<method name="setCallback" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="callback" type="android.app.ActionBar.Callback"> +</parameter> +</method> +<method name="setCustomNavigationView" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="view" type="android.view.View"> +</parameter> +</method> +<method name="setDisplayOptions" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="options" type="int"> +</parameter> +</method> +<method name="setDividerDrawable" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="d" type="android.graphics.drawable.Drawable"> +</parameter> +</method> +<method name="setNavigationMode" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="mode" type="int"> +</parameter> +</method> +<method name="setSubtitle" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="subtitle" type="java.lang.CharSequence"> +</parameter> +</method> +<method name="setTitle" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="title" type="java.lang.CharSequence"> +</parameter> +</method> +<method name="updateActionMenu" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<field name="DISPLAY_HIDE_HOME" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="DISPLAY_USE_LOGO" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="NAVIGATION_MODE_CUSTOM" + type="int" + transient="false" + volatile="false" + value="3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="NAVIGATION_MODE_DROPDOWN_LIST" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="NAVIGATION_MODE_NORMAL" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="NAVIGATION_MODE_TABS" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +<interface name="ActionBar.Callback" + abstract="true" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="onActionItemSelected" + return="boolean" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="item" type="android.view.MenuItem"> +</parameter> +</method> +<method name="onContextItemSelected" + return="boolean" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="modeId" type="int"> +</parameter> +<parameter name="item" type="android.view.MenuItem"> +</parameter> +</method> +<method name="onCreateActionMenu" + return="boolean" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="menu" type="android.view.Menu"> +</parameter> +</method> +<method name="onCreateContextMode" + return="boolean" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="modeId" type="int"> +</parameter> +<parameter name="menu" type="android.view.Menu"> +</parameter> +</method> +<method name="onPrepareContextMode" + return="boolean" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="modeId" type="int"> +</parameter> +<parameter name="menu" type="android.view.Menu"> +</parameter> +</method> +<method name="onUpdateActionMenu" + return="boolean" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="menu" type="android.view.Menu"> +</parameter> +</method> +</interface> +<class name="ActionBar.SimpleCallback" + extends="java.lang.Object" + abstract="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<implements name="android.app.ActionBar.Callback"> +</implements> +<constructor name="ActionBar.SimpleCallback" + type="android.app.ActionBar.SimpleCallback" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<method name="onActionItemSelected" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="item" type="android.view.MenuItem"> +</parameter> +</method> +<method name="onContextItemSelected" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="modeId" type="int"> +</parameter> +<parameter name="item" type="android.view.MenuItem"> +</parameter> +</method> +<method name="onCreateActionMenu" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="menu" type="android.view.Menu"> +</parameter> +</method> +<method name="onCreateContextMode" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="modeId" type="int"> +</parameter> +<parameter name="menu" type="android.view.Menu"> +</parameter> +</method> +<method name="onPrepareContextMode" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="modeId" type="int"> +</parameter> +<parameter name="menu" type="android.view.Menu"> +</parameter> +</method> +<method name="onUpdateActionMenu" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="menu" type="android.view.Menu"> +</parameter> +</method> +</class> <class name="Activity" extends="android.view.ContextThemeWrapper" abstract="false" @@ -19433,6 +19969,17 @@ <parameter name="child" type="android.app.Activity"> </parameter> </method> +<method name="getActionBar" + return="android.app.ActionBar" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getApplication" return="android.app.Application" abstract="false" @@ -63956,7 +64503,7 @@ <method name="drawText" return="void" abstract="false" - native="true" + native="false" synchronized="false" static="false" final="false" @@ -186757,6 +187304,19 @@ visibility="public" > </method> +<method name="hasFeature" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="feature" type="int"> +</parameter> +</method> <method name="hasSoftInputMode" return="boolean" abstract="false" @@ -187407,6 +187967,17 @@ visibility="protected" > </field> +<field name="FEATURE_ACTION_BAR" + type="int" + transient="false" + volatile="false" + value="9" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="FEATURE_CONTEXT_MENU" type="int" transient="false" diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java new file mode 100644 index 0000000..e28d3d3 --- /dev/null +++ b/core/java/android/app/ActionBar.java @@ -0,0 +1,253 @@ +/* + * 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 android.app; + +import android.graphics.drawable.Drawable; +import android.view.ActionBarView; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; + +/** + * This is the public interface to the contextual ActionBar. + * The ActionBar acts as a replacement for the title bar in Activities. + * It provides facilities for creating toolbar actions as well as + * methods of navigating around an application. + */ +public abstract class ActionBar { + /** + * Normal/standard navigation mode. Consists of either a logo or icon + * and title text with an optional subtitle. Clicking any of these elements + * will dispatch onActionItemSelected to the registered Callback with + * a MenuItem with item ID android.R.id.home. + */ + public static final int NAVIGATION_MODE_NORMAL = 0; + + /** + * Dropdown list navigation mode. Instead of static title text this mode + * presents a dropdown menu for navigation within the activity. + */ + public static final int NAVIGATION_MODE_DROPDOWN_LIST = 1; + + /** + * Tab navigation mode. Instead of static title text this mode + * presents a series of tabs for navigation within the activity. + */ + public static final int NAVIGATION_MODE_TABS = 2; + + /** + * Custom navigation mode. This navigation mode is set implicitly whenever + * a custom navigation view is set. See {@link #setCustomNavigationView(View)}. + */ + public static final int NAVIGATION_MODE_CUSTOM = 3; + + /** + * Use logo instead of icon if available. This flag will cause appropriate + * navigation modes to use a wider logo in place of the standard icon. + */ + public static final int DISPLAY_USE_LOGO = 0x1; + + /** + * Hide 'home' elements in this action bar, leaving more space for other + * navigation elements. This includes logo and icon. + */ + public static final int DISPLAY_HIDE_HOME = 0x2; + + /** + * Set the callback that the ActionBar will use to handle events + * and populate menus. + * @param callback Callback to use + */ + public abstract void setCallback(Callback callback); + + /** + * Set a custom navigation view. + * + * Custom navigation views appear between the application icon and + * any action buttons and may use any space available there. Common + * use cases for custom navigation views might include an address bar + * for a browser or other navigation mechanisms that do not translate + * well to provided navigation modes. + * + * Setting a non-null custom navigation view will also set the + * navigation mode to NAVMODE_CUSTOM. + * + * @param view Custom navigation view to place in the ActionBar. + */ + public abstract void setCustomNavigationView(View view); + + /** + * Set the ActionBar's title. + * + * This is set automatically to the name of your Activity, + * but may be changed here. + * + * @param title Title text + */ + public abstract void setTitle(CharSequence title); + + /** + * Set the ActionBar's subtitle. + * + * The subtitle is usually displayed as a second line of text + * under the title. Good for extended descriptions of activity state. + * + * @param subtitle Subtitle text. + */ + public abstract void setSubtitle(CharSequence subtitle); + + /** + * Set the navigation mode. + * + * @param mode One of {@link #NAVIGATION_MODE_NORMAL}, {@link #NAVIGATION_MODE_DROPDOWN_LIST}, + * {@link #NAVIGATION_MODE_TABS}, or {@link #NAVIGATION_MODE_CUSTOM}. + */ + public abstract void setNavigationMode(int mode); + + /** + * Set display options. + * + * @param options A combination of the bits defined by the DISPLAY_ constants + * defined in ActionBar. + */ + public abstract void setDisplayOptions(int options); + + /** + * Set the ActionBar's background. + * + * @param d Background drawable + */ + public abstract void setBackgroundDrawable(Drawable d); + + /** + * Set a drawable to use as a divider between sections of the ActionBar. + * + * @param d Divider drawable + */ + public abstract void setDividerDrawable(Drawable d); + + /** + * @return The current custom navigation view. + */ + public abstract View getCustomNavigationView(); + + /** + * @return The current ActionBar title. + */ + public abstract CharSequence getTitle(); + + /** + * @return The current ActionBar subtitle. + */ + public abstract CharSequence getSubtitle(); + + /** + * @return The current navigation mode. + */ + public abstract int getNavigationMode(); + + /** + * @return The current set of display options. + */ + public abstract int getDisplayOptions(); + + /** + * Request an update of the items in the action menu. + * This will result in a call to Callback.onUpdateActionMenu(Menu) + * and the ActionBar will update based on any changes made there. + */ + public abstract void updateActionMenu(); + + /** + * Callback interface for ActionBar events. + */ + public interface Callback { + /** + * Initialize the always-visible contents of the action bar. + * You should place your menu items into <var>menu</var>. + * + * <p>This is only called once, the first time the action bar is displayed. + * + * @param menu The action menu in which to place your items. + * @return You must return true for actions to be displayed; + * if you return false they will not be shown. + * + * @see #onActionItemSelected(MenuItem) + */ + public boolean onCreateActionMenu(Menu menu); + + /** + * Update the action bar. This is called in response to {@link #updateActionMenu()} + * calls, which may be application-initiated or the result of changing fragment state. + * + * @return true if the action bar should update based on altered menu contents, + * false if no changes are necessary. + */ + public boolean onUpdateActionMenu(Menu menu); + + /** + * This hook is called whenever an item in your action bar is selected. + * The default implementation simply returns false to have the normal + * processing happen (sending a message to its handler). You can use this + * method for any items for which you would like to do processing without + * those other facilities. + * + * @param item The action bar item that was selected. + * @return boolean Return false to allow normal menu processing to proceed, + * true to consume it here. + */ + public boolean onActionItemSelected(MenuItem item); + + /* + * In progress + */ + public boolean onCreateContextMode(int modeId, Menu menu); + public boolean onPrepareContextMode(int modeId, Menu menu); + public boolean onContextItemSelected(int modeId, MenuItem item); + } + + /** + * Simple stub implementations of ActionBar.Callback methods. + * Extend this if you only need a subset of Callback functionality. + */ + public static class SimpleCallback implements Callback { + public boolean onCreateActionMenu(Menu menu) { + return false; + } + + public boolean onUpdateActionMenu(Menu menu) { + return false; + } + + public boolean onActionItemSelected(MenuItem item) { + return false; + } + + public boolean onCreateContextMode(int modeId, Menu menu) { + return false; + } + + public boolean onPrepareContextMode(int modeId, Menu menu) { + return false; + } + + public boolean onContextItemSelected(int modeId, MenuItem item) { + return false; + } + } + +} diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index aa3cb69..21c6d2a 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -16,14 +16,16 @@ package android.app; -import com.android.internal.policy.PolicyManager; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.HashMap; import android.content.ComponentCallbacks; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; -import android.content.Intent; import android.content.IIntentSender; +import android.content.Intent; import android.content.IntentSender; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; @@ -50,6 +52,7 @@ import android.util.Config; import android.util.EventLog; import android.util.Log; import android.util.SparseArray; +import android.view.ActionBarView; import android.view.ContextMenu; import android.view.ContextThemeWrapper; import android.view.InflateException; @@ -69,10 +72,10 @@ import android.view.View.OnCreateContextMenuListener; import android.view.ViewGroup.LayoutParams; import android.view.accessibility.AccessibilityEvent; import android.widget.AdapterView; +import android.widget.LinearLayout; -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.HashMap; +import com.android.internal.app.SplitActionBar; +import com.android.internal.policy.PolicyManager; /** * An activity is a single, focused thing that the user can do. Almost all @@ -650,6 +653,7 @@ public class Activity extends ContextThemeWrapper /*package*/ boolean mWindowAdded = false; /*package*/ boolean mVisibleFromServer = false; /*package*/ boolean mVisibleFromClient = true; + /*package*/ ActionBar mActionBar = null; private CharSequence mTitle; private int mTitleColor = 0; @@ -1793,7 +1797,19 @@ public class Activity extends ContextThemeWrapper public View findViewById(int id) { return getWindow().findViewById(id); } - + + /** + * Retrieve a reference to this activity's ActionBar. + * + * <p><em>Note:</em> The ActionBar is initialized when a content view + * is set. This function will return null if called before {@link #setContentView} + * or {@link #addContentView}. + * @return The Activity's ActionBar, or null if it does not have one. + */ + public ActionBar getActionBar() { + return mActionBar; + } + /** * Finds a fragment that was identified by the given id either when inflated * from XML or as the container ID when added in a transaction. This only @@ -1805,6 +1821,27 @@ public class Activity extends ContextThemeWrapper } /** + * Creates a new ActionBar, locates the inflated ActionBarView, + * initializes the ActionBar with the view, and sets mActionBar. + */ + private void initActionBar() { + if (!getWindow().hasFeature(Window.FEATURE_ACTION_BAR)) { + return; + } + + ActionBarView view = (ActionBarView) findViewById(com.android.internal.R.id.action_bar); + if (view != null) { + LinearLayout splitView = + (LinearLayout) findViewById(com.android.internal.R.id.context_action_bar); + if (splitView != null) { + mActionBar = new SplitActionBar(view, splitView); + } + } else { + Log.e(TAG, "Could not create action bar; view not found in window decor."); + } + } + + /** * Set the activity content from a layout resource. The resource will be * inflated, adding all top-level views to the activity. * @@ -1812,6 +1849,7 @@ public class Activity extends ContextThemeWrapper */ public void setContentView(int layoutResID) { getWindow().setContentView(layoutResID); + initActionBar(); } /** @@ -1823,6 +1861,7 @@ public class Activity extends ContextThemeWrapper */ public void setContentView(View view) { getWindow().setContentView(view); + initActionBar(); } /** @@ -1835,6 +1874,7 @@ public class Activity extends ContextThemeWrapper */ public void setContentView(View view, ViewGroup.LayoutParams params) { getWindow().setContentView(view, params); + initActionBar(); } /** @@ -1846,6 +1886,7 @@ public class Activity extends ContextThemeWrapper */ public void addContentView(View view, ViewGroup.LayoutParams params) { getWindow().addContentView(view, params); + initActionBar(); } /** diff --git a/core/java/android/view/ActionBarView.java b/core/java/android/view/ActionBarView.java new file mode 100644 index 0000000..941ef21 --- /dev/null +++ b/core/java/android/view/ActionBarView.java @@ -0,0 +1,625 @@ +/* + * 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 android.view; + +import java.util.ArrayList; + +import android.app.ActionBar; +import android.app.Activity; +import android.app.ActionBar.Callback; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.res.TypedArray; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.SparseArray; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.internal.R; +import com.android.internal.view.menu.ActionMenu; +import com.android.internal.view.menu.ActionMenuItem; + +/** + * @hide + */ +public class ActionBarView extends ViewGroup { + private static final String TAG = "ActionBarView"; + + // TODO: This must be defined in the default theme + private static final int CONTENT_HEIGHT_DIP = 50; + private static final int CONTENT_PADDING_DIP = 3; + private static final int CONTENT_SPACING_DIP = 6; + private static final int CONTENT_ACTION_SPACING_DIP = 12; + + /** + * Display options applied by default + */ + public static final int DISPLAY_DEFAULT = 0; + + /** + * Display options that require re-layout as opposed to a simple invalidate + */ + private static final int DISPLAY_RELAYOUT_MASK = ActionBar.DISPLAY_USE_LOGO; + + private final int mContentHeight; + + private int mNavigationMode; + private int mDisplayOptions; + private int mSpacing; + private int mActionSpacing; + private CharSequence mTitle; + private CharSequence mSubtitle; + private Drawable mIcon; + private Drawable mLogo; + private Drawable mDivider; + + private ImageView mIconView; + private ImageView mLogoView; + private TextView mTitleView; + private TextView mSubtitleView; + private View mNavigationView; + + private boolean mShowMenu; + + private ActionMenuItem mLogoNavItem; + private ActionMenu mNavMenu; + private ActionMenu mActionMenu; + private ActionMenu mOptionsMenu; + + private SparseArray<ActionMenu> mContextMenus; + + private Callback mCallback; + + private final ArrayList<ActionView> mActions = new ArrayList<ActionView>(); + private final OnClickListener mActionClickHandler = new OnClickListener() { + public void onClick(View v) { + ActionView av = (ActionView) v; + ActionMenuItem item = (ActionMenuItem) av.menuItem; + + if (!mCallback.onActionItemSelected(item)) { + item.invoke(); + } + } + }; + + private OnClickListener mHomeClickListener = null; + + public ActionBarView(Context context, AttributeSet attrs) { + super(context, attrs); + + final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + mContentHeight = (int) (CONTENT_HEIGHT_DIP * metrics.density + 0.5f); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar); + + final int colorFilter = a.getColor(R.styleable.ActionBar_colorFilter, 0); + + if (colorFilter != 0) { + final Drawable d = getBackground(); + d.setDither(true); + d.setColorFilter(new PorterDuffColorFilter(colorFilter, PorterDuff.Mode.OVERLAY)); + } + + ApplicationInfo info = context.getApplicationInfo(); + PackageManager pm = context.getPackageManager(); + mNavigationMode = a.getInt(R.styleable.ActionBar_navigationMode, ActionBar.NAVIGATION_MODE_NORMAL); + mTitle = a.getText(R.styleable.ActionBar_title); + mSubtitle = a.getText(R.styleable.ActionBar_subtitle); + mDisplayOptions = a.getInt(R.styleable.ActionBar_displayOptions, DISPLAY_DEFAULT); + + mLogo = a.getDrawable(R.styleable.ActionBar_logo); + if (mLogo == null) { + mLogo = info.loadLogo(pm); + } + mIcon = a.getDrawable(R.styleable.ActionBar_icon); + if (mIcon == null) { + mIcon = info.loadIcon(pm); + } + mDivider = a.getDrawable(R.styleable.ActionBar_divider); + + Drawable background = a.getDrawable(R.styleable.ActionBar_background); + if (background != null) { + setBackgroundDrawable(background); + } + + final int customNavId = a.getResourceId(R.styleable.ActionBar_customNavigationLayout, 0); + if (customNavId != 0) { + LayoutInflater inflater = LayoutInflater.from(context); + mNavigationView = (View) inflater.inflate(customNavId, null); + mNavigationMode = ActionBar.NAVIGATION_MODE_CUSTOM; + } + + a.recycle(); + + // TODO: Set this in the theme + int padding = (int) (CONTENT_PADDING_DIP * metrics.density + 0.5f); + setPadding(padding, padding, padding, padding); + + mSpacing = (int) (CONTENT_SPACING_DIP * metrics.density + 0.5f); + mActionSpacing = (int) (CONTENT_ACTION_SPACING_DIP * metrics.density + 0.5f); + + if (mLogo != null || mIcon != null || mTitle != null) { + mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle); + mHomeClickListener = new OnClickListener() { + public void onClick(View v) { + if (mCallback != null) { + mCallback.onActionItemSelected(mLogoNavItem); + } + } + }; + } + + mContextMenus = new SparseArray<ActionMenu>(); + } + + private boolean initOptionsMenu() { + final Context context = getContext(); + if (!(context instanceof Activity)) { + return false; + } + + final Activity activity = (Activity) context; + ActionMenu optionsMenu = new ActionMenu(context); + if (activity.onCreateOptionsMenu(optionsMenu)) { + mOptionsMenu = optionsMenu; + return true; + } + + return false; + } + + public void setCallback(Callback callback) { + final Context context = getContext(); + mCallback = callback; + + ActionMenu actionMenu = new ActionMenu(context); + if (callback.onCreateActionMenu(actionMenu)) { + mActionMenu = actionMenu; + performUpdateActionMenu(); + } + } + + public void setCustomNavigationView(View view) { + mNavigationView = view; + if (view != null) { + setNavigationMode(ActionBar.NAVIGATION_MODE_CUSTOM); + } + requestLayout(); + } + + public void setDividerDrawable(Drawable d) { + mDivider = d; + } + + public CharSequence getTitle() { + return mTitle; + } + + public void setTitle(CharSequence title) { + mTitle = title; + if (mTitleView != null) { + mTitleView.setText(title); + } + if (mLogoNavItem != null) { + mLogoNavItem.setTitle(title); + } + } + + public CharSequence getSubtitle() { + return mSubtitle; + } + + public void setSubtitle(CharSequence subtitle) { + mSubtitle = subtitle; + if (mSubtitleView != null) { + mSubtitleView.setText(subtitle); + } + } + + public void setDisplayOptions(int options) { + final int flagsChanged = options & mDisplayOptions; + mDisplayOptions = options; + if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) { + requestLayout(); + } else { + invalidate(); + } + } + + public void setNavigationMode(int mode) { + if (mode != mNavigationMode) { + mNavigationMode = mode; + requestLayout(); + } + } + + public View getCustomNavigationView() { + return mNavigationView; + } + + public int getNavigationMode() { + return mNavigationMode; + } + + public int getDisplayOptions() { + return mDisplayOptions; + } + + private ActionView findActionViewForItem(MenuItem item) { + final ArrayList<ActionView> actions = mActions; + final int actionCount = actions.size(); + for (int i = 0; i < actionCount; i++) { + ActionView av = actions.get(i); + if (av.menuItem.equals(item)) { + return av; + } + } + return null; + } + + public void setContextMode(int mode) { + Callback callback = mCallback; + if (callback == null) { + throw new IllegalStateException( + "Attempted to set ActionBar context mode with no callback"); + } + + ActionMenu menu = mContextMenus.get(mode); + if (menu == null) { + // Initialize the new mode + menu = new ActionMenu(getContext()); + + if (!callback.onCreateContextMode(mode, menu)) { + throw new IllegalArgumentException( + "ActionBar callback does not know how to create context mode " + mode); + } + mContextMenus.put(mode, menu); + } + + if (callback.onPrepareContextMode(mode, menu)) { + // TODO Set mode, animate, etc. + } + } + + public void exitContextMode() { + // TODO Turn off context mode; go back to normal. + } + + public void updateActionMenu() { + final ActionMenu menu = mActionMenu; + if (menu == null || mCallback == null || !mCallback.onUpdateActionMenu(menu)) { + return; + } + performUpdateActionMenu(); + } + + private void performUpdateActionMenu() { + final ActionMenu menu = mActionMenu; + if (menu == null) { + return; + } + final Context context = getContext(); + + int childCount = getChildCount(); + int childIndex = 0; + while (childIndex < childCount) { + View v = getChildAt(childIndex); + if (v instanceof ActionView) { + detachViewFromParent(childIndex); + childCount--; + } else { + childIndex++; + } + } + + ArrayList<ActionView> detachedViews = new ArrayList<ActionView>(mActions); + final int itemCount = menu.size(); + for (int i = 0; i < itemCount; i++) { + final MenuItem item = menu.getItem(i); + + boolean newView = false; + ActionView actionView = findActionViewForItem(item); + if (actionView == null) { + actionView = new ActionView(context); + newView = true; + } + actionView.actionId = item.getItemId(); + actionView.menuItem = item; + actionView.actionLabel = item.getTitle(); + actionView.setAdjustViewBounds(true); + actionView.setImageDrawable(item.getIcon()); + actionView.setOnClickListener(mActionClickHandler); + + LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.MATCH_PARENT, LayoutParams.ITEM_TYPE_ACTION); + actionView.setLayoutParams(layoutParams); + + if (newView) { + addView(actionView); + mActions.add(actionView); + } else { + attachViewToParent(actionView, -1, layoutParams); + detachedViews.remove(actionView); + actionView.invalidate(); + } + } + + final int detachedCount = detachedViews.size(); + for (int i = 0; i < detachedCount; i++) { + removeDetachedView(detachedViews.get(i), false); + } + + requestLayout(); + } + + public void addAction(int id, Drawable icon, CharSequence label, OnActionListener listener) { + ActionView actionView = new ActionView(getContext()); + actionView.actionId = id; + actionView.actionLabel = label; + actionView.actionListener = listener; + actionView.setAdjustViewBounds(true); + actionView.setImageDrawable(icon); + actionView.setOnClickListener(mActionClickHandler); + + actionView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.MATCH_PARENT, LayoutParams.ITEM_TYPE_ACTION)); + + addView(actionView); + mActions.add(actionView); + + requestLayout(); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + if ((mDisplayOptions & ActionBar.DISPLAY_HIDE_HOME) == 0) { + if (mLogo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) { + mLogoView = new ImageView(getContext()); + mLogoView.setAdjustViewBounds(true); + mLogoView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.MATCH_PARENT, LayoutParams.ITEM_TYPE_ICON)); + mLogoView.setImageDrawable(mLogo); + mLogoView.setClickable(true); + mLogoView.setOnClickListener(mHomeClickListener); + addView(mLogoView); + } else if (mIcon != null) { + mIconView = new ImageView(getContext()); + mIconView.setAdjustViewBounds(true); + mIconView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.MATCH_PARENT, LayoutParams.ITEM_TYPE_ICON)); + mIconView.setImageDrawable(mIcon); + mIconView.setClickable(true); + mIconView.setOnClickListener(mHomeClickListener); + addView(mIconView); + } + } + + switch (mNavigationMode) { + case ActionBar.NAVIGATION_MODE_NORMAL: + if (mLogoView == null) { + LayoutInflater inflater = LayoutInflater.from(getContext()); + mTitleView = (TextView) inflater.inflate(R.layout.action_bar_title_item, null); + mTitleView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT, LayoutParams.ITEM_TYPE_TITLE)); + if (mTitle != null) { + mTitleView.setText(mTitle); + } + mTitleView.setClickable(true); + mTitleView.setOnClickListener(mHomeClickListener); + addView(mTitleView); + } + break; + + case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST: + throw new UnsupportedOperationException( + "Dropdown list navigation isn't supported yet!"); + + case ActionBar.NAVIGATION_MODE_TABS: + throw new UnsupportedOperationException( + "Tab navigation isn't supported yet!"); + + case ActionBar.NAVIGATION_MODE_CUSTOM: + if (mNavigationView != null) { + mNavigationView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT, LayoutParams.ITEM_TYPE_CUSTOM_NAV)); + addView(mNavigationView); + } + break; + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + if (widthMode != MeasureSpec.EXACTLY) { + throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + + "with android:layout_width=\"match_parent\" (or fill_parent)"); + } + + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + if (heightMode != MeasureSpec.AT_MOST) { + throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + + "with android:layout_height=\"wrap_content\""); + } + + int contentWidth = MeasureSpec.getSize(widthMeasureSpec); + + int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight(); + int childSpecHeight = MeasureSpec.makeMeasureSpec(mContentHeight - getPaddingTop() - + getPaddingBottom(), MeasureSpec.AT_MOST); + + if (mLogoView != null) { + availableWidth = measureChildView(mLogoView, availableWidth, childSpecHeight, mSpacing); + } + if (mIconView != null) { + availableWidth = measureChildView(mIconView, availableWidth, childSpecHeight, mSpacing); + } + + final ArrayList<ActionView> actions = mActions; + final int actionCount = actions.size(); + for (int i = 0; i < actionCount; i++) { + ActionView action = actions.get(i); + availableWidth = measureChildView(action, availableWidth, + childSpecHeight, mActionSpacing); + } + + switch (mNavigationMode) { + case ActionBar.NAVIGATION_MODE_NORMAL: + if (mTitleView != null) { + availableWidth = measureChildView(mTitleView, availableWidth, + childSpecHeight, mSpacing); + } + break; + case ActionBar.NAVIGATION_MODE_CUSTOM: + if (mNavigationView != null) { + availableWidth = measureChildView(mNavigationView, availableWidth, + childSpecHeight, mSpacing); + } + break; + } + + setMeasuredDimension(contentWidth, mContentHeight); + } + + private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) { + measureChild(child, + MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), + childSpecHeight); + + availableWidth -= child.getMeasuredWidth(); + availableWidth -= spacing; + + return availableWidth; + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + int x = getPaddingLeft(); + final int y = getPaddingTop(); + final int contentHeight = b - t - getPaddingTop() - getPaddingBottom(); + + if (mLogoView != null) { + x += positionChild(mLogoView, x, y, contentHeight) + mSpacing; + } + if (mIconView != null) { + x += positionChild(mIconView, x, y, contentHeight) + mSpacing; + } + + switch (mNavigationMode) { + case ActionBar.NAVIGATION_MODE_NORMAL: + if (mTitleView != null) { + x += positionChild(mTitleView, x, y, contentHeight) + mSpacing; + } + break; + + case ActionBar.NAVIGATION_MODE_CUSTOM: + if (mNavigationView != null) { + x += positionChild(mNavigationView, x, y, contentHeight) + mSpacing; + } + break; + } + + x = r - l - getPaddingRight(); + + final int count = mActions.size(); + for (int i = count - 1; i >= 0; i--) { + ActionView action = mActions.get(i); + x -= (positionChildInverse(action, x, y, contentHeight) + mActionSpacing); + } + } + + private int positionChild(View child, int x, int y, int contentHeight) { + int childWidth = child.getMeasuredWidth(); + int childHeight = child.getMeasuredHeight(); + int childTop = y + (contentHeight - childHeight) / 2; + + child.layout(x, childTop, x + childWidth, childTop + childHeight); + + return childWidth; + } + + private int positionChildInverse(View child, int x, int y, int contentHeight) { + int childWidth = child.getMeasuredWidth(); + int childHeight = child.getMeasuredHeight(); + int childTop = y + (contentHeight - childHeight) / 2; + + child.layout(x - childWidth, childTop, x, childTop + childHeight); + + return childWidth; + } + + @Override + public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { + return new ViewGroup.LayoutParams(getContext(), attrs); + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p != null && p instanceof LayoutParams; + } + + private static class LayoutParams extends ViewGroup.LayoutParams { + static final int ITEM_TYPE_UNKNOWN = -1; + static final int ITEM_TYPE_ICON = 0; + static final int ITEM_TYPE_TITLE = 1; + static final int ITEM_TYPE_CUSTOM_NAV = 2; + static final int ITEM_TYPE_ACTION = 3; + static final int ITEM_TYPE_MORE = 4; + + int type = ITEM_TYPE_UNKNOWN; + + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + } + + public LayoutParams(int width, int height) { + super(width, height); + } + + public LayoutParams(int width, int height, int type) { + this(width, height); + this.type = type; + } + + + public LayoutParams(ViewGroup.LayoutParams source) { + super(source); + } + } + + public interface OnActionListener { + void onAction(int id); + } + + private static class ActionView extends ImageView { + int actionId; + CharSequence actionLabel; + OnActionListener actionListener; + MenuItem menuItem; + + public ActionView(Context context) { + super(context); + } + } +} diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java index 46c805c..a37d83d 100644 --- a/core/java/android/view/MenuInflater.java +++ b/core/java/android/view/MenuInflater.java @@ -16,9 +16,8 @@ package android.view; -import com.android.internal.view.menu.MenuItemImpl; - import java.io.IOException; +import java.lang.reflect.Method; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -30,6 +29,8 @@ import android.content.res.XmlResourceParser; import android.util.AttributeSet; import android.util.Xml; +import com.android.internal.view.menu.MenuItemImpl; + /** * This class is used to instantiate menu XML files into Menu objects. * <p> @@ -166,6 +167,41 @@ public class MenuInflater { } } + private static class InflatedOnMenuItemClickListener + implements MenuItem.OnMenuItemClickListener { + private static final Class[] PARAM_TYPES = new Class[] { MenuItem.class }; + + private Context mContext; + private Method mMethod; + + public InflatedOnMenuItemClickListener(Context context, String methodName) { + mContext = context; + Class c = context.getClass(); + try { + mMethod = c.getMethod(methodName, PARAM_TYPES); + } catch (Exception e) { + InflateException ex = new InflateException( + "Couldn't resolve menu item onClick handler " + methodName + + " in class " + c.getName()); + ex.initCause(e); + throw ex; + } + } + + public boolean onMenuItemClick(MenuItem item) { + try { + if (mMethod.getReturnType() == Boolean.TYPE) { + return (Boolean) mMethod.invoke(mContext, item); + } else { + mMethod.invoke(mContext, item); + return true; + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + /** * State for the current menu. * <p> @@ -205,6 +241,8 @@ public class MenuInflater { private boolean itemVisible; private boolean itemEnabled; + private String itemListenerMethodName; + private static final int defaultGroupId = NO_ID; private static final int defaultItemId = NO_ID; private static final int defaultItemCategory = 0; @@ -276,6 +314,7 @@ public class MenuInflater { itemChecked = a.getBoolean(com.android.internal.R.styleable.MenuItem_checked, defaultItemChecked); itemVisible = a.getBoolean(com.android.internal.R.styleable.MenuItem_visible, groupVisible); itemEnabled = a.getBoolean(com.android.internal.R.styleable.MenuItem_enabled, groupEnabled); + itemListenerMethodName = a.getString(com.android.internal.R.styleable.MenuItem_onClick); a.recycle(); @@ -299,8 +338,13 @@ public class MenuInflater { .setIcon(itemIconResId) .setAlphabeticShortcut(itemAlphabeticShortcut) .setNumericShortcut(itemNumericShortcut); + + if (itemListenerMethodName != null) { + item.setOnMenuItemClickListener( + new InflatedOnMenuItemClickListener(mContext, itemListenerMethodName)); + } - if (itemCheckable >= 2) { + if (itemCheckable >= 2 && item instanceof MenuItemImpl) { ((MenuItemImpl) item).setExclusiveCheckable(true); } } diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 7dd5085..e1ff4e8 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -61,6 +61,13 @@ public abstract class Window { @hide */ public static final int FEATURE_OPENGL = 8; + /** + * Flag for enabling the Action Bar. + * This is enabled by default for some devices. The Action Bar + * replaces the title bar and provides an alternate location + * for an on-screen menu button on some devices. + */ + public static final int FEATURE_ACTION_BAR = 9; /** Flag for setting the progress bar's visibility to VISIBLE */ public static final int PROGRESS_VISIBILITY_ON = -1; /** Flag for setting the progress bar's visibility to GONE */ @@ -981,6 +988,16 @@ public abstract class Window { { return mFeatures; } + + /** + * Query for the availability of a certain feature. + * + * @param feature The feature ID to check + * @return true if the feature is enabled, false otherwise. + */ + public boolean hasFeature(int feature) { + return (getFeatures() & (1 << feature)) != 0; + } /** * Return the feature bits that are being implemented by this Window. diff --git a/core/java/com/android/internal/app/SplitActionBar.java b/core/java/com/android/internal/app/SplitActionBar.java new file mode 100644 index 0000000..4e19e04 --- /dev/null +++ b/core/java/com/android/internal/app/SplitActionBar.java @@ -0,0 +1,97 @@ +/* + * 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.internal.app; + +import android.app.ActionBar; +import android.graphics.drawable.Drawable; +import android.view.ActionBarView; +import android.view.View; +import android.widget.LinearLayout; + +/** + * SplitActionBar is the ActionBar implementation used + * by small-screen devices. It expects to split contextual + * modes across both the ActionBarView at the top of the screen + * and a horizontal LinearLayout at the bottom which is normally + * hidden. + */ +public class SplitActionBar extends ActionBar { + private ActionBarView mActionView; + private LinearLayout mContextView; + + public SplitActionBar(ActionBarView view, LinearLayout contextView) { + mActionView = view; + mContextView = contextView; + } + + public void setCallback(Callback callback) { + mActionView.setCallback(callback); + } + + public void setCustomNavigationView(View view) { + mActionView.setCustomNavigationView(view); + } + + public void setTitle(CharSequence title) { + mActionView.setTitle(title); + } + + public void setSubtitle(CharSequence subtitle) { + mActionView.setSubtitle(subtitle); + } + + public void setNavigationMode(int mode) { + mActionView.setNavigationMode(mode); + } + + public void setDisplayOptions(int options) { + mActionView.setDisplayOptions(options); + } + + public void setBackgroundDrawable(Drawable d) { + mActionView.setBackgroundDrawable(d); + } + + public void setDividerDrawable(Drawable d) { + mActionView.setDividerDrawable(d); + } + + public View getCustomNavigationView() { + return mActionView.getCustomNavigationView(); + } + + public CharSequence getTitle() { + return mActionView.getTitle(); + } + + public CharSequence getSubtitle() { + return mActionView.getSubtitle(); + } + + public int getNavigationMode() { + return mActionView.getNavigationMode(); + } + + public int getDisplayOptions() { + return mActionView.getDisplayOptions(); + } + + public void updateActionMenu() { + mActionView.updateActionMenu(); + } + +} diff --git a/core/java/com/android/internal/view/menu/ActionMenu.java b/core/java/com/android/internal/view/menu/ActionMenu.java new file mode 100644 index 0000000..3d44ebc --- /dev/null +++ b/core/java/com/android/internal/view/menu/ActionMenu.java @@ -0,0 +1,263 @@ +/* + * 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.internal.view.menu; + +import java.util.ArrayList; +import java.util.List; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.SubMenu; + +/** + * @hide + */ +public class ActionMenu implements Menu { + private Context mContext; + + private boolean mIsQwerty; + + private ArrayList<ActionMenuItem> mItems; + + public ActionMenu(Context context) { + mContext = context; + mItems = new ArrayList<ActionMenuItem>(); + } + + public Context getContext() { + return mContext; + } + + public MenuItem add(CharSequence title) { + return add(0, 0, 0, title); + } + + public MenuItem add(int titleRes) { + return add(0, 0, 0, titleRes); + } + + public MenuItem add(int groupId, int itemId, int order, int titleRes) { + return add(groupId, itemId, order, mContext.getResources().getString(titleRes)); + } + + public MenuItem add(int groupId, int itemId, int order, CharSequence title) { + ActionMenuItem item = new ActionMenuItem(getContext(), + groupId, itemId, 0, order, title); + mItems.add(order, item); + return item; + } + + public int addIntentOptions(int groupId, int itemId, int order, + ComponentName caller, Intent[] specifics, Intent intent, int flags, + MenuItem[] outSpecificItems) { + PackageManager pm = mContext.getPackageManager(); + final List<ResolveInfo> lri = + pm.queryIntentActivityOptions(caller, specifics, intent, 0); + final int N = lri != null ? lri.size() : 0; + + if ((flags & FLAG_APPEND_TO_GROUP) == 0) { + removeGroup(groupId); + } + + for (int i=0; i<N; i++) { + final ResolveInfo ri = lri.get(i); + Intent rintent = new Intent( + ri.specificIndex < 0 ? intent : specifics[ri.specificIndex]); + rintent.setComponent(new ComponentName( + ri.activityInfo.applicationInfo.packageName, + ri.activityInfo.name)); + final MenuItem item = add(groupId, itemId, order, ri.loadLabel(pm)) + .setIcon(ri.loadIcon(pm)) + .setIntent(rintent); + if (outSpecificItems != null && ri.specificIndex >= 0) { + outSpecificItems[ri.specificIndex] = item; + } + } + + return N; + } + + public SubMenu addSubMenu(CharSequence title) { + // TODO Implement submenus + return null; + } + + public SubMenu addSubMenu(int titleRes) { + // TODO Implement submenus + return null; + } + + public SubMenu addSubMenu(int groupId, int itemId, int order, + CharSequence title) { + // TODO Implement submenus + return null; + } + + public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) { + // TODO Implement submenus + return null; + } + + public void clear() { + mItems.clear(); + } + + public void close() { + } + + private int findItemIndex(int id) { + final ArrayList<ActionMenuItem> items = mItems; + final int itemCount = items.size(); + for (int i = 0; i < itemCount; i++) { + if (items.get(i).getItemId() == id) { + return i; + } + } + + return -1; + } + + public MenuItem findItem(int id) { + return mItems.get(findItemIndex(id)); + } + + public MenuItem getItem(int index) { + return mItems.get(index); + } + + public boolean hasVisibleItems() { + final ArrayList<ActionMenuItem> items = mItems; + final int itemCount = items.size(); + + for (int i = 0; i < itemCount; i++) { + if (items.get(i).isVisible()) { + return true; + } + } + + return false; + } + + private ActionMenuItem findItemWithShortcut(int keyCode, KeyEvent event) { + // TODO Make this smarter. + final boolean qwerty = mIsQwerty; + final ArrayList<ActionMenuItem> items = mItems; + final int itemCount = items.size(); + + for (int i = 0; i < itemCount; i++) { + ActionMenuItem item = items.get(i); + final char shortcut = qwerty ? item.getAlphabeticShortcut() : + item.getNumericShortcut(); + if (keyCode == shortcut) { + return item; + } + } + return null; + } + + public boolean isShortcutKey(int keyCode, KeyEvent event) { + return findItemWithShortcut(keyCode, event) != null; + } + + public boolean performIdentifierAction(int id, int flags) { + final int index = findItemIndex(id); + if (index < 0) { + return false; + } + + return mItems.get(index).invoke(); + } + + public boolean performShortcut(int keyCode, KeyEvent event, int flags) { + ActionMenuItem item = findItemWithShortcut(keyCode, event); + if (item == null) { + return false; + } + + return item.invoke(); + } + + public void removeGroup(int groupId) { + final ArrayList<ActionMenuItem> items = mItems; + int itemCount = items.size(); + int i = 0; + while (i < itemCount) { + if (items.get(i).getGroupId() == groupId) { + items.remove(i); + itemCount--; + } else { + i++; + } + } + } + + public void removeItem(int id) { + mItems.remove(findItemIndex(id)); + } + + public void setGroupCheckable(int group, boolean checkable, + boolean exclusive) { + final ArrayList<ActionMenuItem> items = mItems; + final int itemCount = items.size(); + + for (int i = 0; i < itemCount; i++) { + ActionMenuItem item = items.get(i); + if (item.getGroupId() == group) { + item.setCheckable(checkable); + item.setExclusiveCheckable(exclusive); + } + } + } + + public void setGroupEnabled(int group, boolean enabled) { + final ArrayList<ActionMenuItem> items = mItems; + final int itemCount = items.size(); + + for (int i = 0; i < itemCount; i++) { + ActionMenuItem item = items.get(i); + if (item.getGroupId() == group) { + item.setEnabled(enabled); + } + } + } + + public void setGroupVisible(int group, boolean visible) { + final ArrayList<ActionMenuItem> items = mItems; + final int itemCount = items.size(); + + for (int i = 0; i < itemCount; i++) { + ActionMenuItem item = items.get(i); + if (item.getGroupId() == group) { + item.setVisible(visible); + } + } + } + + public void setQwertyMode(boolean isQwerty) { + mIsQwerty = isQwerty; + } + + public int size() { + return mItems.size(); + } +} diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java new file mode 100644 index 0000000..47d5fb9 --- /dev/null +++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java @@ -0,0 +1,221 @@ +/* + * 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.internal.view.menu; + +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.view.MenuItem; +import android.view.SubMenu; +import android.view.ContextMenu.ContextMenuInfo; + +/** + * @hide + */ +public class ActionMenuItem implements MenuItem { + private final int mId; + private final int mGroup; + private final int mCategoryOrder; + private final int mOrdering; + + private CharSequence mTitle; + private CharSequence mTitleCondensed; + private Intent mIntent; + private char mShortcutNumericChar; + private char mShortcutAlphabeticChar; + + private Drawable mIconDrawable; + private int mIconResId = NO_ICON; + + private Context mContext; + + private MenuItem.OnMenuItemClickListener mClickListener; + + private static final int NO_ICON = 0; + + private int mFlags = ENABLED; + private static final int CHECKABLE = 0x00000001; + private static final int CHECKED = 0x00000002; + private static final int EXCLUSIVE = 0x00000004; + private static final int HIDDEN = 0x00000008; + private static final int ENABLED = 0x00000010; + + public ActionMenuItem(Context context, int group, int id, int categoryOrder, int ordering, + CharSequence title) { + mContext = context; + mId = id; + mGroup = group; + mCategoryOrder = categoryOrder; + mOrdering = ordering; + mTitle = title; + } + + public char getAlphabeticShortcut() { + return mShortcutAlphabeticChar; + } + + public int getGroupId() { + return mGroup; + } + + public Drawable getIcon() { + return mIconDrawable; + } + + public Intent getIntent() { + return mIntent; + } + + public int getItemId() { + return mId; + } + + public ContextMenuInfo getMenuInfo() { + return null; + } + + public char getNumericShortcut() { + return mShortcutNumericChar; + } + + public int getOrder() { + return mOrdering; + } + + public SubMenu getSubMenu() { + return null; + } + + public CharSequence getTitle() { + return mTitle; + } + + public CharSequence getTitleCondensed() { + return mTitleCondensed; + } + + public boolean hasSubMenu() { + return false; + } + + public boolean isCheckable() { + return (mFlags & CHECKABLE) != 0; + } + + public boolean isChecked() { + return (mFlags & CHECKED) != 0; + } + + public boolean isEnabled() { + return (mFlags & ENABLED) != 0; + } + + public boolean isVisible() { + return (mFlags & HIDDEN) == 0; + } + + public MenuItem setAlphabeticShortcut(char alphaChar) { + mShortcutAlphabeticChar = alphaChar; + return this; + } + + public MenuItem setCheckable(boolean checkable) { + mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0); + return this; + } + + public ActionMenuItem setExclusiveCheckable(boolean exclusive) { + mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0); + return this; + } + + public MenuItem setChecked(boolean checked) { + mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0); + return this; + } + + public MenuItem setEnabled(boolean enabled) { + mFlags = (mFlags & ~ENABLED) | (enabled ? ENABLED : 0); + return this; + } + + public MenuItem setIcon(Drawable icon) { + mIconDrawable = icon; + mIconResId = NO_ICON; + return this; + } + + public MenuItem setIcon(int iconRes) { + mIconResId = iconRes; + mIconDrawable = mContext.getResources().getDrawable(iconRes); + return this; + } + + public MenuItem setIntent(Intent intent) { + mIntent = intent; + return this; + } + + public MenuItem setNumericShortcut(char numericChar) { + mShortcutNumericChar = numericChar; + return this; + } + + public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) { + mClickListener = menuItemClickListener; + return this; + } + + public MenuItem setShortcut(char numericChar, char alphaChar) { + mShortcutNumericChar = numericChar; + mShortcutAlphabeticChar = alphaChar; + return this; + } + + public MenuItem setTitle(CharSequence title) { + mTitle = title; + return this; + } + + public MenuItem setTitle(int title) { + mTitle = mContext.getResources().getString(title); + return this; + } + + public MenuItem setTitleCondensed(CharSequence title) { + mTitleCondensed = title; + return this; + } + + public MenuItem setVisible(boolean visible) { + mFlags = (mFlags & HIDDEN) | (visible ? 0 : HIDDEN); + return this; + } + + public boolean invoke() { + if (mClickListener != null && mClickListener.onMenuItemClick(this)) { + return true; + } + + if (mIntent != null) { + mContext.startActivity(mIntent); + return true; + } + + return false; + } +} diff --git a/core/res/res/drawable/action_bar_background.xml b/core/res/res/drawable/action_bar_background.xml new file mode 100644 index 0000000..3929d7f --- /dev/null +++ b/core/res/res/drawable/action_bar_background.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <gradient + android:startColor="#ffd1d2d4" + android:endColor="#ff85878a" + android:angle="270" /> +</shape> diff --git a/core/res/res/drawable/action_bar_divider.xml b/core/res/res/drawable/action_bar_divider.xml new file mode 100644 index 0000000..414309f --- /dev/null +++ b/core/res/res/drawable/action_bar_divider.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <gradient + android:startColor="#ffe1e2e4" + android:endColor="#ff95979a" + android:angle="270" /> +</shape> diff --git a/core/res/res/layout/action_bar_title_item.xml b/core/res/res/layout/action_bar_title_item.xml new file mode 100644 index 0000000..d7f7c13 --- /dev/null +++ b/core/res/res/layout/action_bar_title_item.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<TextView + xmlns:android="http://schemas.android.com/apk/res/android" + + android:singleLine="true" + android:ellipsize="end" + android:textAppearance="?android:attr/textAppearanceMediumInverse" /> diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml new file mode 100644 index 0000000..01a4b42 --- /dev/null +++ b/core/res/res/layout/screen_action_bar.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- +This is an optimized layout for a screen with the Action Bar enabled. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:fitsSystemWindows="true"> + <ActionBarView android:id="@+id/action_bar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="?android:attr/windowActionBarStyle" /> + <FrameLayout android:id="@android:id/content" + android:layout_width="match_parent" + android:layout_height="0dip" + android:layout_weight="1" + android:foregroundGravity="fill_horizontal|top" + android:foreground="?android:attr/windowContentOverlay" /> + <LinearLayout android:id="@+id/context_action_bar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="?android:attr/windowActionBarStyle" + android:visibility="gone" /> +</LinearLayout> + diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 1449b02..e7b83c7 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -244,6 +244,13 @@ {@link android.R.styleable#WindowAnimation}. --> <attr name="windowAnimationStyle" format="reference" /> + <!-- Flag indicating whether this window should have an Action Bar + in place of the usual title bar. --> + <attr name="windowActionBar" format="boolean" /> + + <!-- Reference to a style for the Action Bar --> + <attr name="windowActionBarStyle" format="reference" /> + <!-- Defines the default soft input state that this window would like when it is displayed. --> <attr name="windowSoftInputMode"> @@ -948,6 +955,8 @@ <attr name="textColor" /> <attr name="backgroundDimEnabled" /> <attr name="backgroundDimAmount" /> + <attr name="windowActionBar" /> + <attr name="windowActionBarStyle" /> </declare-styleable> <!-- The set of attributes that describe a AlertDialog's theme. --> @@ -3243,6 +3252,10 @@ <!-- Whether the item is enabled. --> <attr name="enabled" /> + <!-- Name of a method on the Context used to inflate the menu that will be + called when the item is clicked. --> + <attr name="onClick" /> + </declare-styleable> <!-- **************************************************************** --> @@ -3762,4 +3775,42 @@ <attr name="withClass" format="string" /> </declare-styleable> + <!-- Attributes used to style the Action Bar. --> + <declare-styleable name="ActionBar"> + <!-- The type of navigation to use. --> + <attr name="navigationMode"> + <!-- Normal static title text --> + <enum name="normal" value="0" /> + <!-- The action bar will use a drop-down selection in place of title text. --> + <enum name="dropdownList" value="1" /> + <!-- The action bar will use a series of horizontal tabs in place of title text. --> + <enum name="tabBar" value="2" /> + </attr> + <!-- Options affecting how the action bar is displayed. --> + <attr name="displayOptions"> + <flag name="useLogo" value="1" /> + <flag name="hideHome" value="2" /> + </attr> + <!-- Specifies the color used to style the action bar. --> + <attr name="colorFilter" format="color" /> + <!-- Specifies title text used for navigationMode="normal" --> + <attr name="title" /> + <!-- Specifies subtitle text used for navigationMode="normal" --> + <attr name="subtitle" format="string" /> + <!-- Specifies a style to use for title text. --> + <attr name="titleTextStyle" format="reference" /> + <!-- Specifies a style to use for subtitle text. --> + <attr name="subtitleTextStyle" format="reference" /> + <!-- Specifies the drawable used for the application icon. --> + <attr name="icon" /> + <!-- Specifies the drawable used for the application logo. --> + <attr name="logo" /> + <!-- Specifies the drawable used for item dividers. --> + <attr name="divider" /> + <!-- Specifies a background drawable for the action bar. --> + <attr name="background" /> + <!-- Specifies a layout for custom navigation. Overrides navigationMode. --> + <attr name="customNavigationLayout" format="reference" /> + </declare-styleable> + </resources> diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index 8b6af71..e607fad 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -68,4 +68,5 @@ <item type="id" name="accountPreferences" /> <item type="id" name="smallIcon" /> <item type="id" name="custom" /> + <item type="id" name="home" /> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index fe27174..9055970 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1275,5 +1275,15 @@ <public type="attr" name="withExpression" /> <public type="attr" name="withClass" /> <public type="attr" name="allContactsName" /> + <public type="attr" name="windowActionBar" /> + <public type="attr" name="windowActionBarStyle" /> + <public type="attr" name="navigationMode" /> + <public type="attr" name="displayOptions" /> + <public type="attr" name="subtitle" /> + <public type="attr" name="customNavigationLayout" /> + + <public type="id" name="home" /> + + <public type="style" name="Theme.WithActionBar" /> </resources> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index f9b0667..73c3444 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -840,4 +840,10 @@ <item name="android:paddingBottom">1dip</item> <item name="android:background">@android:drawable/bottom_bar</item> </style> + + <style name="ActionBar"> + <item name="android:background">@android:drawable/action_bar_background</item> + <item name="android:displayOptions">useLogo</item> + <item name="android:divider">@android:drawable/action_bar_divider</item> + </style> </resources> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index d585d9e..32c5f47 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -115,6 +115,8 @@ <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground</item> <item name="android:windowAnimationStyle">@android:style/Animation.Activity</item> <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item> + <item name="windowActionBar">false</item> + <item name="windowActionBarStyle">@android:style/ActionBar</item> <!-- Dialog attributes --> <item name="alertDialogStyle">@android:style/AlertDialog</item> @@ -521,5 +523,9 @@ <item name="android:windowAnimationStyle">@android:style/Animation.RecentApplications</item> <item name="android:textColor">@android:color/secondary_text_nofocus</item> </style> + + <style name="Theme.WithActionBar"> + <item name="android:windowActionBar">true</item> + </style> </resources> diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 5592b6d..20d9f26 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -21,13 +21,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; - -import com.android.internal.view.menu.ContextMenuBuilder; -import com.android.internal.view.menu.MenuBuilder; -import com.android.internal.view.menu.MenuDialogHelper; -import com.android.internal.view.menu.MenuView; -import com.android.internal.view.menu.SubMenuBuilder; - import android.app.KeyguardManager; import android.app.SearchManager; import android.content.ActivityNotFoundException; @@ -51,6 +44,7 @@ import android.util.Config; import android.util.EventLog; import android.util.Log; import android.util.SparseArray; +import android.view.ActionBarView; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.KeyCharacterMap; @@ -75,6 +69,12 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; +import com.android.internal.view.menu.ContextMenuBuilder; +import com.android.internal.view.menu.MenuBuilder; +import com.android.internal.view.menu.MenuDialogHelper; +import com.android.internal.view.menu.MenuView; +import com.android.internal.view.menu.SubMenuBuilder; + /** * Android-specific Window. * <p> @@ -105,6 +105,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private LayoutInflater mLayoutInflater; private TextView mTitleView; + + private ActionBarView mActionBar; private DrawableFeatureState[] mDrawables; @@ -258,6 +260,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public void setTitle(CharSequence title) { if (mTitleView != null) { mTitleView.setText(title); + } else if (mActionBar != null) { + mActionBar.setTitle(title); } mTitle = title; } @@ -2067,6 +2071,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) { requestFeature(FEATURE_NO_TITLE); + } else if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBar, false)) { + // Don't allow an action bar if there is no title. + requestFeature(FEATURE_ACTION_BAR); } if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) { @@ -2150,6 +2157,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // If the window is floating, we need a dialog layout if (mIsFloating) { layoutResource = com.android.internal.R.layout.dialog_title; + } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) { + layoutResource = com.android.internal.R.layout.screen_action_bar; } else { layoutResource = com.android.internal.R.layout.screen_title; } @@ -2234,6 +2243,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } else { mTitleView.setText(mTitle); } + } else { + mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar); + if (mActionBar != null) { + if (mActionBar.getTitle() == null) { + mActionBar.setTitle(mTitle); + } + } } } } |
