Use ActionBarSherlock v4.4 AAR
@ -1,28 +0,0 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:0.5.+'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'android-library'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 17
|
||||
buildToolsVersion "17.0.0"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 7
|
||||
targetSdkVersion 17
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:support-v4:18.0.0'
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system use,
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
android.library=true
|
||||
# Project target.
|
||||
target=android-17
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="100" android:versionName="4.2.0" package="com.actionbarsherlock">
|
||||
|
||||
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="16"/>
|
||||
|
||||
</manifest>
|
@ -1,144 +0,0 @@
|
||||
package android.support.v4.app;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/** I'm in ur package. Stealing ur variables. */
|
||||
public abstract class Watson extends FragmentActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "Watson";
|
||||
|
||||
/** Fragment interface for menu creation callback. */
|
||||
public interface OnCreateOptionsMenuListener {
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater);
|
||||
}
|
||||
/** Fragment interface for menu preparation callback. */
|
||||
public interface OnPrepareOptionsMenuListener {
|
||||
public void onPrepareOptionsMenu(Menu menu);
|
||||
}
|
||||
/** Fragment interface for menu item selection callback. */
|
||||
public interface OnOptionsItemSelectedListener {
|
||||
public boolean onOptionsItemSelected(MenuItem item);
|
||||
}
|
||||
|
||||
private ArrayList<Fragment> mCreatedMenus;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Sherlock menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public boolean onCreatePanelMenu(int featureId, Menu menu) {
|
||||
if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] featureId: " + featureId + ", menu: " + menu);
|
||||
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
boolean result = onCreateOptionsMenu(menu);
|
||||
if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] activity create result: " + result);
|
||||
|
||||
MenuInflater inflater = getSupportMenuInflater();
|
||||
boolean show = false;
|
||||
ArrayList<Fragment> newMenus = null;
|
||||
if (mFragments.mAdded != null) {
|
||||
for (int i = 0; i < mFragments.mAdded.size(); i++) {
|
||||
Fragment f = mFragments.mAdded.get(i);
|
||||
if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible && f instanceof OnCreateOptionsMenuListener) {
|
||||
show = true;
|
||||
((OnCreateOptionsMenuListener)f).onCreateOptionsMenu(menu, inflater);
|
||||
if (newMenus == null) {
|
||||
newMenus = new ArrayList<Fragment>();
|
||||
}
|
||||
newMenus.add(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mCreatedMenus != null) {
|
||||
for (int i = 0; i < mCreatedMenus.size(); i++) {
|
||||
Fragment f = mCreatedMenus.get(i);
|
||||
if (newMenus == null || !newMenus.contains(f)) {
|
||||
f.onDestroyOptionsMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mCreatedMenus = newMenus;
|
||||
|
||||
if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] fragments create result: " + show);
|
||||
result |= show;
|
||||
|
||||
if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] returning " + result);
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreparePanel(int featureId, View view, Menu menu) {
|
||||
if (DEBUG) Log.d(TAG, "[onPreparePanel] featureId: " + featureId + ", view: " + view + " menu: " + menu);
|
||||
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
boolean result = onPrepareOptionsMenu(menu);
|
||||
if (DEBUG) Log.d(TAG, "[onPreparePanel] activity prepare result: " + result);
|
||||
|
||||
boolean show = false;
|
||||
if (mFragments.mAdded != null) {
|
||||
for (int i = 0; i < mFragments.mAdded.size(); i++) {
|
||||
Fragment f = mFragments.mAdded.get(i);
|
||||
if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible && f instanceof OnPrepareOptionsMenuListener) {
|
||||
show = true;
|
||||
((OnPrepareOptionsMenuListener)f).onPrepareOptionsMenu(menu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) Log.d(TAG, "[onPreparePanel] fragments prepare result: " + show);
|
||||
result |= show;
|
||||
|
||||
result &= menu.hasVisibleItems();
|
||||
if (DEBUG) Log.d(TAG, "[onPreparePanel] returning " + result);
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
if (DEBUG) Log.d(TAG, "[onMenuItemSelected] featureId: " + featureId + ", item: " + item);
|
||||
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
if (onOptionsItemSelected(item)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mFragments.mAdded != null) {
|
||||
for (int i = 0; i < mFragments.mAdded.size(); i++) {
|
||||
Fragment f = mFragments.mAdded.get(i);
|
||||
if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible && f instanceof OnOptionsItemSelectedListener) {
|
||||
if (((OnOptionsItemSelectedListener)f).onOptionsItemSelected(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract boolean onCreateOptionsMenu(Menu menu);
|
||||
|
||||
public abstract boolean onPrepareOptionsMenu(Menu menu);
|
||||
|
||||
public abstract boolean onOptionsItemSelected(MenuItem item);
|
||||
|
||||
public abstract MenuInflater getSupportMenuInflater();
|
||||
}
|
@ -1,794 +0,0 @@
|
||||
package com.actionbarsherlock;
|
||||
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import com.actionbarsherlock.app.ActionBar;
|
||||
import com.actionbarsherlock.internal.ActionBarSherlockCompat;
|
||||
import com.actionbarsherlock.internal.ActionBarSherlockNative;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
/**
|
||||
* <p>Helper for implementing the action bar design pattern across all versions
|
||||
* of Android.</p>
|
||||
*
|
||||
* <p>This class will manage interaction with a custom action bar based on the
|
||||
* Android 4.0 source code. The exposed API mirrors that of its native
|
||||
* counterpart and you should refer to its documentation for instruction.</p>
|
||||
*
|
||||
* @author Jake Wharton <jakewharton@gmail.com>
|
||||
*/
|
||||
public abstract class ActionBarSherlock {
|
||||
protected static final String TAG = "ActionBarSherlock";
|
||||
protected static final boolean DEBUG = false;
|
||||
|
||||
private static final Class<?>[] CONSTRUCTOR_ARGS = new Class[] { Activity.class, int.class };
|
||||
private static final HashMap<Implementation, Class<? extends ActionBarSherlock>> IMPLEMENTATIONS =
|
||||
new HashMap<Implementation, Class<? extends ActionBarSherlock>>();
|
||||
|
||||
static {
|
||||
//Register our two built-in implementations
|
||||
registerImplementation(ActionBarSherlockCompat.class);
|
||||
registerImplementation(ActionBarSherlockNative.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Denotes an implementation of ActionBarSherlock which provides an
|
||||
* action bar-enhanced experience.</p>
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Implementation {
|
||||
static final int DEFAULT_API = -1;
|
||||
static final int DEFAULT_DPI = -1;
|
||||
|
||||
int api() default DEFAULT_API;
|
||||
int dpi() default DEFAULT_DPI;
|
||||
}
|
||||
|
||||
|
||||
/** Activity interface for menu creation callback. */
|
||||
public interface OnCreatePanelMenuListener {
|
||||
public boolean onCreatePanelMenu(int featureId, Menu menu);
|
||||
}
|
||||
/** Activity interface for menu creation callback. */
|
||||
public interface OnCreateOptionsMenuListener {
|
||||
public boolean onCreateOptionsMenu(Menu menu);
|
||||
}
|
||||
/** Activity interface for menu item selection callback. */
|
||||
public interface OnMenuItemSelectedListener {
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item);
|
||||
}
|
||||
/** Activity interface for menu item selection callback. */
|
||||
public interface OnOptionsItemSelectedListener {
|
||||
public boolean onOptionsItemSelected(MenuItem item);
|
||||
}
|
||||
/** Activity interface for menu preparation callback. */
|
||||
public interface OnPreparePanelListener {
|
||||
public boolean onPreparePanel(int featureId, View view, Menu menu);
|
||||
}
|
||||
/** Activity interface for menu preparation callback. */
|
||||
public interface OnPrepareOptionsMenuListener {
|
||||
public boolean onPrepareOptionsMenu(Menu menu);
|
||||
}
|
||||
/** Activity interface for action mode finished callback. */
|
||||
public interface OnActionModeFinishedListener {
|
||||
public void onActionModeFinished(ActionMode mode);
|
||||
}
|
||||
/** Activity interface for action mode started callback. */
|
||||
public interface OnActionModeStartedListener {
|
||||
public void onActionModeStarted(ActionMode mode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If set, the logic in these classes will assume that an {@link Activity}
|
||||
* is dispatching all of the required events to the class. This flag should
|
||||
* only be used internally or if you are creating your own base activity
|
||||
* modeled after one of the included types (e.g., {@code SherlockActivity}).
|
||||
*/
|
||||
public static final int FLAG_DELEGATE = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Register an ActionBarSherlock implementation.
|
||||
*
|
||||
* @param implementationClass Target implementation class which extends
|
||||
* {@link ActionBarSherlock}. This class must also be annotated with
|
||||
* {@link Implementation}.
|
||||
*/
|
||||
public static void registerImplementation(Class<? extends ActionBarSherlock> implementationClass) {
|
||||
if (!implementationClass.isAnnotationPresent(Implementation.class)) {
|
||||
throw new IllegalArgumentException("Class " + implementationClass.getSimpleName() + " is not annotated with @Implementation");
|
||||
} else if (IMPLEMENTATIONS.containsValue(implementationClass)) {
|
||||
if (DEBUG) Log.w(TAG, "Class " + implementationClass.getSimpleName() + " already registered");
|
||||
return;
|
||||
}
|
||||
|
||||
Implementation impl = implementationClass.getAnnotation(Implementation.class);
|
||||
if (DEBUG) Log.i(TAG, "Registering " + implementationClass.getSimpleName() + " with qualifier " + impl);
|
||||
IMPLEMENTATIONS.put(impl, implementationClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister an ActionBarSherlock implementation. <strong>This should be
|
||||
* considered very volatile and you should only use it if you know what
|
||||
* you are doing.</strong> You have been warned.
|
||||
*
|
||||
* @param implementationClass Target implementation class.
|
||||
* @return Boolean indicating whether the class was removed.
|
||||
*/
|
||||
public static boolean unregisterImplementation(Class<? extends ActionBarSherlock> implementationClass) {
|
||||
return IMPLEMENTATIONS.values().remove(implementationClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap an activity with an action bar abstraction which will enable the
|
||||
* use of a custom implementation on platforms where a native version does
|
||||
* not exist.
|
||||
*
|
||||
* @param activity Activity to wrap.
|
||||
* @return Instance to interact with the action bar.
|
||||
*/
|
||||
public static ActionBarSherlock wrap(Activity activity) {
|
||||
return wrap(activity, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap an activity with an action bar abstraction which will enable the
|
||||
* use of a custom implementation on platforms where a native version does
|
||||
* not exist.
|
||||
*
|
||||
* @param activity Owning activity.
|
||||
* @param flags Option flags to control behavior.
|
||||
* @return Instance to interact with the action bar.
|
||||
*/
|
||||
public static ActionBarSherlock wrap(Activity activity, int flags) {
|
||||
//Create a local implementation map we can modify
|
||||
HashMap<Implementation, Class<? extends ActionBarSherlock>> impls =
|
||||
new HashMap<Implementation, Class<? extends ActionBarSherlock>>(IMPLEMENTATIONS);
|
||||
boolean hasQualfier;
|
||||
|
||||
/* DPI FILTERING */
|
||||
hasQualfier = false;
|
||||
for (Implementation key : impls.keySet()) {
|
||||
//Only honor TVDPI as a specific qualifier
|
||||
if (key.dpi() == DisplayMetrics.DENSITY_TV) {
|
||||
hasQualfier = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasQualfier) {
|
||||
final boolean isTvDpi = activity.getResources().getDisplayMetrics().densityDpi == DisplayMetrics.DENSITY_TV;
|
||||
for (Iterator<Implementation> keys = impls.keySet().iterator(); keys.hasNext(); ) {
|
||||
int keyDpi = keys.next().dpi();
|
||||
if ((isTvDpi && keyDpi != DisplayMetrics.DENSITY_TV)
|
||||
|| (!isTvDpi && keyDpi == DisplayMetrics.DENSITY_TV)) {
|
||||
keys.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* API FILTERING */
|
||||
hasQualfier = false;
|
||||
for (Implementation key : impls.keySet()) {
|
||||
if (key.api() != Implementation.DEFAULT_API) {
|
||||
hasQualfier = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasQualfier) {
|
||||
final int runtimeApi = Build.VERSION.SDK_INT;
|
||||
int bestApi = 0;
|
||||
for (Iterator<Implementation> keys = impls.keySet().iterator(); keys.hasNext(); ) {
|
||||
int keyApi = keys.next().api();
|
||||
if (keyApi > runtimeApi) {
|
||||
keys.remove();
|
||||
} else if (keyApi > bestApi) {
|
||||
bestApi = keyApi;
|
||||
}
|
||||
}
|
||||
for (Iterator<Implementation> keys = impls.keySet().iterator(); keys.hasNext(); ) {
|
||||
if (keys.next().api() != bestApi) {
|
||||
keys.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (impls.size() > 1) {
|
||||
throw new IllegalStateException("More than one implementation matches configuration.");
|
||||
}
|
||||
if (impls.isEmpty()) {
|
||||
throw new IllegalStateException("No implementations match configuration.");
|
||||
}
|
||||
Class<? extends ActionBarSherlock> impl = impls.values().iterator().next();
|
||||
if (DEBUG) Log.i(TAG, "Using implementation: " + impl.getSimpleName());
|
||||
|
||||
try {
|
||||
Constructor<? extends ActionBarSherlock> ctor = impl.getConstructor(CONSTRUCTOR_ARGS);
|
||||
return ctor.newInstance(activity, flags);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Activity which is displaying the action bar. Also used for context. */
|
||||
protected final Activity mActivity;
|
||||
/** Whether delegating actions for the activity or managing ourselves. */
|
||||
protected final boolean mIsDelegate;
|
||||
|
||||
/** Reference to our custom menu inflater which supports action items. */
|
||||
protected MenuInflater mMenuInflater;
|
||||
|
||||
|
||||
|
||||
protected ActionBarSherlock(Activity activity, int flags) {
|
||||
if (DEBUG) Log.d(TAG, "[<ctor>] activity: " + activity + ", flags: " + flags);
|
||||
|
||||
mActivity = activity;
|
||||
mIsDelegate = (flags & FLAG_DELEGATE) != 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the current action bar instance.
|
||||
*
|
||||
* @return Action bar instance.
|
||||
*/
|
||||
public abstract ActionBar getActionBar();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Lifecycle and interaction callbacks when delegating
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Notify action bar of a configuration change event. Should be dispatched
|
||||
* after the call to the superclass implementation.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Override
|
||||
* public void onConfigurationChanged(Configuration newConfig) {
|
||||
* super.onConfigurationChanged(newConfig);
|
||||
* mSherlock.dispatchConfigurationChanged(newConfig);
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @param newConfig The new device configuration.
|
||||
*/
|
||||
public void dispatchConfigurationChanged(Configuration newConfig) {}
|
||||
|
||||
/**
|
||||
* Notify the action bar that the activity has finished its resuming. This
|
||||
* should be dispatched after the call to the superclass implementation.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Override
|
||||
* protected void onPostResume() {
|
||||
* super.onPostResume();
|
||||
* mSherlock.dispatchPostResume();
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*/
|
||||
public void dispatchPostResume() {}
|
||||
|
||||
/**
|
||||
* Notify the action bar that the activity is pausing. This should be
|
||||
* dispatched before the call to the superclass implementation.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Override
|
||||
* protected void onPause() {
|
||||
* mSherlock.dispatchPause();
|
||||
* super.onPause();
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*/
|
||||
public void dispatchPause() {}
|
||||
|
||||
/**
|
||||
* Notify the action bar that the activity is stopping. This should be
|
||||
* called before the superclass implementation.
|
||||
*
|
||||
* <blockquote><p>
|
||||
* @Override
|
||||
* protected void onStop() {
|
||||
* mSherlock.dispatchStop();
|
||||
* super.onStop();
|
||||
* }
|
||||
* </p></blockquote>
|
||||
*/
|
||||
public void dispatchStop() {}
|
||||
|
||||
/**
|
||||
* Indicate that the menu should be recreated by calling
|
||||
* {@link OnCreateOptionsMenuListener#onCreateOptionsMenu(com.actionbarsherlock.view.Menu)}.
|
||||
*/
|
||||
public abstract void dispatchInvalidateOptionsMenu();
|
||||
|
||||
/**
|
||||
* Notify the action bar that it should display its overflow menu if it is
|
||||
* appropriate for the device. The implementation should conditionally
|
||||
* call the superclass method only if this method returns {@code false}.
|
||||
*
|
||||
* <blockquote><p>
|
||||
* @Override
|
||||
* public void openOptionsMenu() {
|
||||
* if (!mSherlock.dispatchOpenOptionsMenu()) {
|
||||
* super.openOptionsMenu();
|
||||
* }
|
||||
* }
|
||||
* </p></blockquote>
|
||||
*
|
||||
* @return {@code true} if the opening of the menu was handled internally.
|
||||
*/
|
||||
public boolean dispatchOpenOptionsMenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the action bar that it should close its overflow menu if it is
|
||||
* appropriate for the device. This implementation should conditionally
|
||||
* call the superclass method only if this method returns {@code false}.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Override
|
||||
* public void closeOptionsMenu() {
|
||||
* if (!mSherlock.dispatchCloseOptionsMenu()) {
|
||||
* super.closeOptionsMenu();
|
||||
* }
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @return {@code true} if the closing of the menu was handled internally.
|
||||
*/
|
||||
public boolean dispatchCloseOptionsMenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the class that the activity has finished its creation. This
|
||||
* should be called after the superclass implementation.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Override
|
||||
* protected void onPostCreate(Bundle savedInstanceState) {
|
||||
* mSherlock.dispatchPostCreate(savedInstanceState);
|
||||
* super.onPostCreate(savedInstanceState);
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @param savedInstanceState If the activity is being re-initialized after
|
||||
* previously being shut down then this Bundle
|
||||
* contains the data it most recently supplied in
|
||||
* {@link Activity#}onSaveInstanceState(Bundle)}.
|
||||
* <strong>Note: Otherwise it is null.</strong>
|
||||
*/
|
||||
public void dispatchPostCreate(Bundle savedInstanceState) {}
|
||||
|
||||
/**
|
||||
* Notify the action bar that the title has changed and the action bar
|
||||
* should be updated to reflect the change. This should be called before
|
||||
* the superclass implementation.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Override
|
||||
* protected void onTitleChanged(CharSequence title, int color) {
|
||||
* mSherlock.dispatchTitleChanged(title, color);
|
||||
* super.onTitleChanged(title, color);
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @param title New activity title.
|
||||
* @param color New activity color.
|
||||
*/
|
||||
public void dispatchTitleChanged(CharSequence title, int color) {}
|
||||
|
||||
/**
|
||||
* Notify the action bar the user has created a key event. This is used to
|
||||
* toggle the display of the overflow action item with the menu key and to
|
||||
* close the action mode or expanded action item with the back key.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Override
|
||||
* public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
* if (mSherlock.dispatchKeyEvent(event)) {
|
||||
* return true;
|
||||
* }
|
||||
* return super.dispatchKeyEvent(event);
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @param event Description of the key event.
|
||||
* @return {@code true} if the event was handled.
|
||||
*/
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the action bar that the Activity has triggered a menu creation
|
||||
* which should happen on the conclusion of {@link Activity#onCreate}. This
|
||||
* will be used to gain a reference to the native menu for native and
|
||||
* overflow binding as well as to indicate when compatibility create should
|
||||
* occur for the first time.
|
||||
*
|
||||
* @param menu Activity native menu.
|
||||
* @return {@code true} since we always want to say that we have a native
|
||||
*/
|
||||
public abstract boolean dispatchCreateOptionsMenu(android.view.Menu menu);
|
||||
|
||||
/**
|
||||
* Notify the action bar that the Activity has triggered a menu preparation
|
||||
* which usually means that the user has requested the overflow menu via a
|
||||
* hardware menu key. You should return the result of this method call and
|
||||
* not call the superclass implementation.
|
||||
*
|
||||
* <blockquote><p>
|
||||
* @Override
|
||||
* public final boolean onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
* return mSherlock.dispatchPrepareOptionsMenu(menu);
|
||||
* }
|
||||
* </p></blockquote>
|
||||
*
|
||||
* @param menu Activity native menu.
|
||||
* @return {@code true} if menu display should proceed.
|
||||
*/
|
||||
public abstract boolean dispatchPrepareOptionsMenu(android.view.Menu menu);
|
||||
|
||||
/**
|
||||
* Notify the action bar that a native options menu item has been selected.
|
||||
* The implementation should return the result of this method call.
|
||||
*
|
||||
* <blockquote><p>
|
||||
* @Override
|
||||
* public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
* return mSherlock.dispatchOptionsItemSelected(item);
|
||||
* }
|
||||
* </p></blockquote>
|
||||
*
|
||||
* @param item Options menu item.
|
||||
* @return @{code true} if the selection was handled.
|
||||
*/
|
||||
public abstract boolean dispatchOptionsItemSelected(android.view.MenuItem item);
|
||||
|
||||
/**
|
||||
* Notify the action bar that the overflow menu has been opened. The
|
||||
* implementation should conditionally return {@code true} if this method
|
||||
* returns {@code true}, otherwise return the result of the superclass
|
||||
* method.
|
||||
*
|
||||
* <blockquote><p>
|
||||
* @Override
|
||||
* public final boolean onMenuOpened(int featureId, android.view.Menu menu) {
|
||||
* if (mSherlock.dispatchMenuOpened(featureId, menu)) {
|
||||
* return true;
|
||||
* }
|
||||
* return super.onMenuOpened(featureId, menu);
|
||||
* }
|
||||
* </p></blockquote>
|
||||
*
|
||||
* @param featureId Window feature which triggered the event.
|
||||
* @param menu Activity native menu.
|
||||
* @return {@code true} if the event was handled by this method.
|
||||
*/
|
||||
public boolean dispatchMenuOpened(int featureId, android.view.Menu menu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the action bar that the overflow menu has been closed. This
|
||||
* method should be called before the superclass implementation.
|
||||
*
|
||||
* <blockquote><p>
|
||||
* @Override
|
||||
* public void onPanelClosed(int featureId, android.view.Menu menu) {
|
||||
* mSherlock.dispatchPanelClosed(featureId, menu);
|
||||
* super.onPanelClosed(featureId, menu);
|
||||
* }
|
||||
* </p></blockquote>
|
||||
*
|
||||
* @param featureId
|
||||
* @param menu
|
||||
*/
|
||||
public void dispatchPanelClosed(int featureId, android.view.Menu menu) {}
|
||||
|
||||
/**
|
||||
* Notify the action bar that the activity has been destroyed. This method
|
||||
* should be called before the superclass implementation.
|
||||
*
|
||||
* <blockquote><p>
|
||||
* @Override
|
||||
* public void onDestroy() {
|
||||
* mSherlock.dispatchDestroy();
|
||||
* super.onDestroy();
|
||||
* }
|
||||
* </p></blockquote>
|
||||
*/
|
||||
public void dispatchDestroy() {}
|
||||
|
||||
public void dispatchSaveInstanceState(Bundle outState) {}
|
||||
|
||||
public void dispatchRestoreInstanceState(Bundle savedInstanceState) {}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Internal method to trigger the menu creation process.
|
||||
*
|
||||
* @return {@code true} if menu creation should proceed.
|
||||
*/
|
||||
protected final boolean callbackCreateOptionsMenu(Menu menu) {
|
||||
if (DEBUG) Log.d(TAG, "[callbackCreateOptionsMenu] menu: " + menu);
|
||||
|
||||
boolean result = true;
|
||||
if (mActivity instanceof OnCreatePanelMenuListener) {
|
||||
OnCreatePanelMenuListener listener = (OnCreatePanelMenuListener)mActivity;
|
||||
result = listener.onCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, menu);
|
||||
} else if (mActivity instanceof OnCreateOptionsMenuListener) {
|
||||
OnCreateOptionsMenuListener listener = (OnCreateOptionsMenuListener)mActivity;
|
||||
result = listener.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
if (DEBUG) Log.d(TAG, "[callbackCreateOptionsMenu] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to trigger the menu preparation process.
|
||||
*
|
||||
* @return {@code true} if menu preparation should proceed.
|
||||
*/
|
||||
protected final boolean callbackPrepareOptionsMenu(Menu menu) {
|
||||
if (DEBUG) Log.d(TAG, "[callbackPrepareOptionsMenu] menu: " + menu);
|
||||
|
||||
boolean result = true;
|
||||
if (mActivity instanceof OnPreparePanelListener) {
|
||||
OnPreparePanelListener listener = (OnPreparePanelListener)mActivity;
|
||||
result = listener.onPreparePanel(Window.FEATURE_OPTIONS_PANEL, null, menu);
|
||||
} else if (mActivity instanceof OnPrepareOptionsMenuListener) {
|
||||
OnPrepareOptionsMenuListener listener = (OnPrepareOptionsMenuListener)mActivity;
|
||||
result = listener.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
if (DEBUG) Log.d(TAG, "[callbackPrepareOptionsMenu] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method for dispatching options menu selection to the owning
|
||||
* activity callback.
|
||||
*
|
||||
* @param item Selected options menu item.
|
||||
* @return {@code true} if the item selection was handled in the callback.
|
||||
*/
|
||||
protected final boolean callbackOptionsItemSelected(MenuItem item) {
|
||||
if (DEBUG) Log.d(TAG, "[callbackOptionsItemSelected] item: " + item.getTitleCondensed());
|
||||
|
||||
boolean result = false;
|
||||
if (mActivity instanceof OnMenuItemSelectedListener) {
|
||||
OnMenuItemSelectedListener listener = (OnMenuItemSelectedListener)mActivity;
|
||||
result = listener.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item);
|
||||
} else if (mActivity instanceof OnOptionsItemSelectedListener) {
|
||||
OnOptionsItemSelectedListener listener = (OnOptionsItemSelectedListener)mActivity;
|
||||
result = listener.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
if (DEBUG) Log.d(TAG, "[callbackOptionsItemSelected] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Query for the availability of a certain feature.
|
||||
*
|
||||
* @param featureId The feature ID to check.
|
||||
* @return {@code true} if feature is enabled, {@code false} otherwise.
|
||||
*/
|
||||
public abstract boolean hasFeature(int featureId);
|
||||
|
||||
/**
|
||||
* Enable extended screen features. This must be called before
|
||||
* {@code setContentView()}. May be called as many times as desired as long
|
||||
* as it is before {@code setContentView()}. If not called, no extended
|
||||
* features will be available. You can not turn off a feature once it is
|
||||
* requested.
|
||||
*
|
||||
* @param featureId The desired features, defined as constants by Window.
|
||||
* @return Returns true if the requested feature is supported and now
|
||||
* enabled.
|
||||
*/
|
||||
public abstract boolean requestFeature(int featureId);
|
||||
|
||||
/**
|
||||
* Set extra options that will influence the UI for this window.
|
||||
*
|
||||
* @param uiOptions Flags specifying extra options for this window.
|
||||
*/
|
||||
public abstract void setUiOptions(int uiOptions);
|
||||
|
||||
/**
|
||||
* Set extra options that will influence the UI for this window. Only the
|
||||
* bits filtered by mask will be modified.
|
||||
*
|
||||
* @param uiOptions Flags specifying extra options for this window.
|
||||
* @param mask Flags specifying which options should be modified. Others
|
||||
* will remain unchanged.
|
||||
*/
|
||||
public abstract void setUiOptions(int uiOptions, int mask);
|
||||
|
||||
/**
|
||||
* Set the content of the activity inside the action bar.
|
||||
*
|
||||
* @param layoutResId Layout resource ID.
|
||||
*/
|
||||
public abstract void setContentView(int layoutResId);
|
||||
|
||||
/**
|
||||
* Set the content of the activity inside the action bar.
|
||||
*
|
||||
* @param view The desired content to display.
|
||||
*/
|
||||
public void setContentView(View view) {
|
||||
if (DEBUG) Log.d(TAG, "[setContentView] view: " + view);
|
||||
|
||||
setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content of the activity inside the action bar.
|
||||
*
|
||||
* @param view The desired content to display.
|
||||
* @param params Layout parameters to apply to the view.
|
||||
*/
|
||||
public abstract void setContentView(View view, ViewGroup.LayoutParams params);
|
||||
|
||||
/**
|
||||
* Variation on {@link #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}
|
||||
* to add an additional content view to the screen. Added after any
|
||||
* existing ones on the screen -- existing views are NOT removed.
|
||||
*
|
||||
* @param view The desired content to display.
|
||||
* @param params Layout parameters for the view.
|
||||
*/
|
||||
public abstract void addContentView(View view, ViewGroup.LayoutParams params);
|
||||
|
||||
/**
|
||||
* Change the title associated with this activity.
|
||||
*/
|
||||
public abstract void setTitle(CharSequence title);
|
||||
|
||||
/**
|
||||
* Change the title associated with this activity.
|
||||
*/
|
||||
public void setTitle(int resId) {
|
||||
if (DEBUG) Log.d(TAG, "[setTitle] resId: " + resId);
|
||||
|
||||
setTitle(mActivity.getString(resId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visibility of the progress bar in the title.
|
||||
* <p>
|
||||
* In order for the progress bar to be shown, the feature must be requested
|
||||
* via {@link #requestWindowFeature(int)}.
|
||||
*
|
||||
* @param visible Whether to show the progress bars in the title.
|
||||
*/
|
||||
public abstract void setProgressBarVisibility(boolean visible);
|
||||
|
||||
/**
|
||||
* Sets the visibility of the indeterminate progress bar in the title.
|
||||
* <p>
|
||||
* In order for the progress bar to be shown, the feature must be requested
|
||||
* via {@link #requestWindowFeature(int)}.
|
||||
*
|
||||
* @param visible Whether to show the progress bars in the title.
|
||||
*/
|
||||
public abstract void setProgressBarIndeterminateVisibility(boolean visible);
|
||||
|
||||
/**
|
||||
* Sets whether the horizontal progress bar in the title should be indeterminate (the circular
|
||||
* is always indeterminate).
|
||||
* <p>
|
||||
* In order for the progress bar to be shown, the feature must be requested
|
||||
* via {@link #requestWindowFeature(int)}.
|
||||
*
|
||||
* @param indeterminate Whether the horizontal progress bar should be indeterminate.
|
||||
*/
|
||||
public abstract void setProgressBarIndeterminate(boolean indeterminate);
|
||||
|
||||
/**
|
||||
* Sets the progress for the progress bars in the title.
|
||||
* <p>
|
||||
* In order for the progress bar to be shown, the feature must be requested
|
||||
* via {@link #requestWindowFeature(int)}.
|
||||
*
|
||||
* @param progress The progress for the progress bar. Valid ranges are from
|
||||
* 0 to 10000 (both inclusive). If 10000 is given, the progress
|
||||
* bar will be completely filled and will fade out.
|
||||
*/
|
||||
public abstract void setProgress(int progress);
|
||||
|
||||
/**
|
||||
* Sets the secondary progress for the progress bar in the title. This
|
||||
* progress is drawn between the primary progress (set via
|
||||
* {@link #setProgress(int)} and the background. It can be ideal for media
|
||||
* scenarios such as showing the buffering progress while the default
|
||||
* progress shows the play progress.
|
||||
* <p>
|
||||
* In order for the progress bar to be shown, the feature must be requested
|
||||
* via {@link #requestWindowFeature(int)}.
|
||||
*
|
||||
* @param secondaryProgress The secondary progress for the progress bar. Valid ranges are from
|
||||
* 0 to 10000 (both inclusive).
|
||||
*/
|
||||
public abstract void setSecondaryProgress(int secondaryProgress);
|
||||
|
||||
/**
|
||||
* Get a menu inflater instance which supports the newer menu attributes.
|
||||
*
|
||||
* @return Menu inflater instance.
|
||||
*/
|
||||
public MenuInflater getMenuInflater() {
|
||||
if (DEBUG) Log.d(TAG, "[getMenuInflater]");
|
||||
|
||||
// Make sure that action views can get an appropriate theme.
|
||||
if (mMenuInflater == null) {
|
||||
if (getActionBar() != null) {
|
||||
mMenuInflater = new MenuInflater(getThemedContext(), mActivity);
|
||||
} else {
|
||||
mMenuInflater = new MenuInflater(mActivity);
|
||||
}
|
||||
}
|
||||
return mMenuInflater;
|
||||
}
|
||||
|
||||
protected abstract Context getThemedContext();
|
||||
|
||||
/**
|
||||
* Start an action mode.
|
||||
*
|
||||
* @param callback Callback that will manage lifecycle events for this
|
||||
* context mode.
|
||||
* @return The ContextMode that was started, or null if it was canceled.
|
||||
* @see ActionMode
|
||||
*/
|
||||
public abstract ActionMode startActionMode(ActionMode.Callback callback);
|
||||
}
|
@ -1,956 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewGroup.MarginLayoutParams;
|
||||
import android.widget.SpinnerAdapter;
|
||||
|
||||
/**
|
||||
* A window feature at the top of the activity that may display the activity title, navigation
|
||||
* modes, and other interactive items.
|
||||
* <p>Beginning with Android 3.0 (API level 11), the action bar appears at the top of an
|
||||
* activity's window when the activity uses the system's {@link
|
||||
* android.R.style#Theme_Holo Holo} theme (or one of its descendant themes), which is the default.
|
||||
* You may otherwise add the action bar by calling {@link
|
||||
* android.view.Window#requestFeature requestFeature(FEATURE_ACTION_BAR)} or by declaring it in a
|
||||
* custom theme with the {@link android.R.styleable#Theme_windowActionBar windowActionBar} property.
|
||||
* <p>By default, the action bar shows the application icon on
|
||||
* the left, followed by the activity title. If your activity has an options menu, you can make
|
||||
* select items accessible directly from the action bar as "action items". You can also
|
||||
* modify various characteristics of the action bar or remove it completely.</p>
|
||||
* <p>From your activity, you can retrieve an instance of {@link ActionBar} by calling {@link
|
||||
* android.app.Activity#getActionBar getActionBar()}.</p>
|
||||
* <p>In some cases, the action bar may be overlayed by another bar that enables contextual actions,
|
||||
* using an {@link android.view.ActionMode}. For example, when the user selects one or more items in
|
||||
* your activity, you can enable an action mode that offers actions specific to the selected
|
||||
* items, with a UI that temporarily replaces the action bar. Although the UI may occupy the
|
||||
* same space, the {@link android.view.ActionMode} APIs are distinct and independent from those for
|
||||
* {@link ActionBar}.
|
||||
* <div class="special reference">
|
||||
* <h3>Developer Guides</h3>
|
||||
* <p>For information about how to use the action bar, including how to add action items, navigation
|
||||
* modes and more, read the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action
|
||||
* Bar</a> developer guide.</p>
|
||||
* </div>
|
||||
*/
|
||||
public abstract class ActionBar {
|
||||
/**
|
||||
* Standard navigation mode. Consists of either a logo or icon
|
||||
* and title text with an optional subtitle. Clicking any of these elements
|
||||
* will dispatch onOptionsItemSelected to the host Activity with
|
||||
* a MenuItem with item ID android.R.id.home.
|
||||
*/
|
||||
public static final int NAVIGATION_MODE_STANDARD = android.app.ActionBar.NAVIGATION_MODE_STANDARD;
|
||||
|
||||
/**
|
||||
* List navigation mode. Instead of static title text this mode
|
||||
* presents a list menu for navigation within the activity.
|
||||
* e.g. this might be presented to the user as a dropdown list.
|
||||
*/
|
||||
public static final int NAVIGATION_MODE_LIST = android.app.ActionBar.NAVIGATION_MODE_LIST;
|
||||
|
||||
/**
|
||||
* 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 = android.app.ActionBar.NAVIGATION_MODE_TABS;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public static final int DISPLAY_USE_LOGO = android.app.ActionBar.DISPLAY_USE_LOGO;
|
||||
|
||||
/**
|
||||
* Show 'home' elements in this action bar, leaving more space for other
|
||||
* navigation elements. This includes logo and icon.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public static final int DISPLAY_SHOW_HOME = android.app.ActionBar.DISPLAY_SHOW_HOME;
|
||||
|
||||
/**
|
||||
* Display the 'home' element such that it appears as an 'up' affordance.
|
||||
* e.g. show an arrow to the left indicating the action that will be taken.
|
||||
*
|
||||
* Set this flag if selecting the 'home' button in the action bar to return
|
||||
* up by a single level in your UI rather than back to the top level or front page.
|
||||
*
|
||||
* <p>Setting this option will implicitly enable interaction with the home/up
|
||||
* button. See {@link #setHomeButtonEnabled(boolean)}.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public static final int DISPLAY_HOME_AS_UP = android.app.ActionBar.DISPLAY_HOME_AS_UP;
|
||||
|
||||
/**
|
||||
* Show the activity title and subtitle, if present.
|
||||
*
|
||||
* @see #setTitle(CharSequence)
|
||||
* @see #setTitle(int)
|
||||
* @see #setSubtitle(CharSequence)
|
||||
* @see #setSubtitle(int)
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public static final int DISPLAY_SHOW_TITLE = android.app.ActionBar.DISPLAY_SHOW_TITLE;
|
||||
|
||||
/**
|
||||
* Show the custom view if one has been set.
|
||||
* @see #setCustomView(View)
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public static final int DISPLAY_SHOW_CUSTOM = android.app.ActionBar.DISPLAY_SHOW_CUSTOM;
|
||||
|
||||
/**
|
||||
* Set the action bar into custom navigation mode, supplying a view
|
||||
* for custom navigation.
|
||||
*
|
||||
* 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 auto-suggesting
|
||||
* address bar for a browser or other navigation mechanisms that do not
|
||||
* translate well to provided navigation modes.
|
||||
*
|
||||
* @param view Custom navigation view to place in the ActionBar.
|
||||
*/
|
||||
public abstract void setCustomView(View view);
|
||||
|
||||
/**
|
||||
* Set the action bar into custom navigation mode, supplying a view
|
||||
* for custom navigation.
|
||||
*
|
||||
* <p>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 auto-suggesting
|
||||
* address bar for a browser or other navigation mechanisms that do not
|
||||
* translate well to provided navigation modes.</p>
|
||||
*
|
||||
* <p>The display option {@link #DISPLAY_SHOW_CUSTOM} must be set for
|
||||
* the custom view to be displayed.</p>
|
||||
*
|
||||
* @param view Custom navigation view to place in the ActionBar.
|
||||
* @param layoutParams How this custom view should layout in the bar.
|
||||
*
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setCustomView(View view, LayoutParams layoutParams);
|
||||
|
||||
/**
|
||||
* Set the action bar into custom navigation mode, supplying a view
|
||||
* for custom navigation.
|
||||
*
|
||||
* <p>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 auto-suggesting
|
||||
* address bar for a browser or other navigation mechanisms that do not
|
||||
* translate well to provided navigation modes.</p>
|
||||
*
|
||||
* <p>The display option {@link #DISPLAY_SHOW_CUSTOM} must be set for
|
||||
* the custom view to be displayed.</p>
|
||||
*
|
||||
* @param resId Resource ID of a layout to inflate into the ActionBar.
|
||||
*
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setCustomView(int resId);
|
||||
|
||||
/**
|
||||
* Set the icon to display in the 'home' section of the action bar.
|
||||
* The action bar will use an icon specified by its style or the
|
||||
* activity icon by default.
|
||||
*
|
||||
* Whether the home section shows an icon or logo is controlled
|
||||
* by the display option {@link #DISPLAY_USE_LOGO}.
|
||||
*
|
||||
* @param resId Resource ID of a drawable to show as an icon.
|
||||
*
|
||||
* @see #setDisplayUseLogoEnabled(boolean)
|
||||
* @see #setDisplayShowHomeEnabled(boolean)
|
||||
*/
|
||||
public abstract void setIcon(int resId);
|
||||
|
||||
/**
|
||||
* Set the icon to display in the 'home' section of the action bar.
|
||||
* The action bar will use an icon specified by its style or the
|
||||
* activity icon by default.
|
||||
*
|
||||
* Whether the home section shows an icon or logo is controlled
|
||||
* by the display option {@link #DISPLAY_USE_LOGO}.
|
||||
*
|
||||
* @param icon Drawable to show as an icon.
|
||||
*
|
||||
* @see #setDisplayUseLogoEnabled(boolean)
|
||||
* @see #setDisplayShowHomeEnabled(boolean)
|
||||
*/
|
||||
public abstract void setIcon(Drawable icon);
|
||||
|
||||
/**
|
||||
* Set the logo to display in the 'home' section of the action bar.
|
||||
* The action bar will use a logo specified by its style or the
|
||||
* activity logo by default.
|
||||
*
|
||||
* Whether the home section shows an icon or logo is controlled
|
||||
* by the display option {@link #DISPLAY_USE_LOGO}.
|
||||
*
|
||||
* @param resId Resource ID of a drawable to show as a logo.
|
||||
*
|
||||
* @see #setDisplayUseLogoEnabled(boolean)
|
||||
* @see #setDisplayShowHomeEnabled(boolean)
|
||||
*/
|
||||
public abstract void setLogo(int resId);
|
||||
|
||||
/**
|
||||
* Set the logo to display in the 'home' section of the action bar.
|
||||
* The action bar will use a logo specified by its style or the
|
||||
* activity logo by default.
|
||||
*
|
||||
* Whether the home section shows an icon or logo is controlled
|
||||
* by the display option {@link #DISPLAY_USE_LOGO}.
|
||||
*
|
||||
* @param logo Drawable to show as a logo.
|
||||
*
|
||||
* @see #setDisplayUseLogoEnabled(boolean)
|
||||
* @see #setDisplayShowHomeEnabled(boolean)
|
||||
*/
|
||||
public abstract void setLogo(Drawable logo);
|
||||
|
||||
/**
|
||||
* Set the adapter and navigation callback for list navigation mode.
|
||||
*
|
||||
* The supplied adapter will provide views for the expanded list as well as
|
||||
* the currently selected item. (These may be displayed differently.)
|
||||
*
|
||||
* The supplied OnNavigationListener will alert the application when the user
|
||||
* changes the current list selection.
|
||||
*
|
||||
* @param adapter An adapter that will provide views both to display
|
||||
* the current navigation selection and populate views
|
||||
* within the dropdown navigation menu.
|
||||
* @param callback An OnNavigationListener that will receive events when the user
|
||||
* selects a navigation item.
|
||||
*/
|
||||
public abstract void setListNavigationCallbacks(SpinnerAdapter adapter,
|
||||
OnNavigationListener callback);
|
||||
|
||||
/**
|
||||
* Set the selected navigation item in list or tabbed navigation modes.
|
||||
*
|
||||
* @param position Position of the item to select.
|
||||
*/
|
||||
public abstract void setSelectedNavigationItem(int position);
|
||||
|
||||
/**
|
||||
* Get the position of the selected navigation item in list or tabbed navigation modes.
|
||||
*
|
||||
* @return Position of the selected item.
|
||||
*/
|
||||
public abstract int getSelectedNavigationIndex();
|
||||
|
||||
/**
|
||||
* Get the number of navigation items present in the current navigation mode.
|
||||
*
|
||||
* @return Number of navigation items.
|
||||
*/
|
||||
public abstract int getNavigationItemCount();
|
||||
|
||||
/**
|
||||
* Set the action bar's title. This will only be displayed if
|
||||
* {@link #DISPLAY_SHOW_TITLE} is set.
|
||||
*
|
||||
* @param title Title to set
|
||||
*
|
||||
* @see #setTitle(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setTitle(CharSequence title);
|
||||
|
||||
/**
|
||||
* Set the action bar's title. This will only be displayed if
|
||||
* {@link #DISPLAY_SHOW_TITLE} is set.
|
||||
*
|
||||
* @param resId Resource ID of title string to set
|
||||
*
|
||||
* @see #setTitle(CharSequence)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setTitle(int resId);
|
||||
|
||||
/**
|
||||
* Set the action bar's subtitle. This will only be displayed if
|
||||
* {@link #DISPLAY_SHOW_TITLE} is set. Set to null to disable the
|
||||
* subtitle entirely.
|
||||
*
|
||||
* @param subtitle Subtitle to set
|
||||
*
|
||||
* @see #setSubtitle(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setSubtitle(CharSequence subtitle);
|
||||
|
||||
/**
|
||||
* Set the action bar's subtitle. This will only be displayed if
|
||||
* {@link #DISPLAY_SHOW_TITLE} is set.
|
||||
*
|
||||
* @param resId Resource ID of subtitle string to set
|
||||
*
|
||||
* @see #setSubtitle(CharSequence)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setSubtitle(int resId);
|
||||
|
||||
/**
|
||||
* Set display options. This changes all display option bits at once. To change
|
||||
* a limited subset of display options, see {@link #setDisplayOptions(int, int)}.
|
||||
*
|
||||
* @param options A combination of the bits defined by the DISPLAY_ constants
|
||||
* defined in ActionBar.
|
||||
*/
|
||||
public abstract void setDisplayOptions(int options);
|
||||
|
||||
/**
|
||||
* Set selected display options. Only the options specified by mask will be changed.
|
||||
* To change all display option bits at once, see {@link #setDisplayOptions(int)}.
|
||||
*
|
||||
* <p>Example: setDisplayOptions(0, DISPLAY_SHOW_HOME) will disable the
|
||||
* {@link #DISPLAY_SHOW_HOME} option.
|
||||
* setDisplayOptions(DISPLAY_SHOW_HOME, DISPLAY_SHOW_HOME | DISPLAY_USE_LOGO)
|
||||
* will enable {@link #DISPLAY_SHOW_HOME} and disable {@link #DISPLAY_USE_LOGO}.
|
||||
*
|
||||
* @param options A combination of the bits defined by the DISPLAY_ constants
|
||||
* defined in ActionBar.
|
||||
* @param mask A bit mask declaring which display options should be changed.
|
||||
*/
|
||||
public abstract void setDisplayOptions(int options, int mask);
|
||||
|
||||
/**
|
||||
* Set whether to display the activity logo rather than the activity icon.
|
||||
* A logo is often a wider, more detailed image.
|
||||
*
|
||||
* <p>To set several display options at once, see the setDisplayOptions methods.
|
||||
*
|
||||
* @param useLogo true to use the activity logo, false to use the activity icon.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setDisplayUseLogoEnabled(boolean useLogo);
|
||||
|
||||
/**
|
||||
* Set whether to include the application home affordance in the action bar.
|
||||
* Home is presented as either an activity icon or logo.
|
||||
*
|
||||
* <p>To set several display options at once, see the setDisplayOptions methods.
|
||||
*
|
||||
* @param showHome true to show home, false otherwise.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setDisplayShowHomeEnabled(boolean showHome);
|
||||
|
||||
/**
|
||||
* Set whether home should be displayed as an "up" affordance.
|
||||
* Set this to true if selecting "home" returns up by a single level in your UI
|
||||
* rather than back to the top level or front page.
|
||||
*
|
||||
* <p>To set several display options at once, see the setDisplayOptions methods.
|
||||
*
|
||||
* @param showHomeAsUp true to show the user that selecting home will return one
|
||||
* level up rather than to the top level of the app.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setDisplayHomeAsUpEnabled(boolean showHomeAsUp);
|
||||
|
||||
/**
|
||||
* Set whether an activity title/subtitle should be displayed.
|
||||
*
|
||||
* <p>To set several display options at once, see the setDisplayOptions methods.
|
||||
*
|
||||
* @param showTitle true to display a title/subtitle if present.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setDisplayShowTitleEnabled(boolean showTitle);
|
||||
|
||||
/**
|
||||
* Set whether a custom view should be displayed, if set.
|
||||
*
|
||||
* <p>To set several display options at once, see the setDisplayOptions methods.
|
||||
*
|
||||
* @param showCustom true if the currently set custom view should be displayed, false otherwise.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setDisplayShowCustomEnabled(boolean showCustom);
|
||||
|
||||
/**
|
||||
* Set the ActionBar's background. This will be used for the primary
|
||||
* action bar.
|
||||
*
|
||||
* @param d Background drawable
|
||||
* @see #setStackedBackgroundDrawable(Drawable)
|
||||
* @see #setSplitBackgroundDrawable(Drawable)
|
||||
*/
|
||||
public abstract void setBackgroundDrawable(Drawable d);
|
||||
|
||||
/**
|
||||
* Set the ActionBar's stacked background. This will appear
|
||||
* in the second row/stacked bar on some devices and configurations.
|
||||
*
|
||||
* @param d Background drawable for the stacked row
|
||||
*/
|
||||
public void setStackedBackgroundDrawable(Drawable d) { }
|
||||
|
||||
/**
|
||||
* Set the ActionBar's split background. This will appear in
|
||||
* the split action bar containing menu-provided action buttons
|
||||
* on some devices and configurations.
|
||||
* <p>You can enable split action bar with {@link android.R.attr#uiOptions}
|
||||
*
|
||||
* @param d Background drawable for the split bar
|
||||
*/
|
||||
public void setSplitBackgroundDrawable(Drawable d) { }
|
||||
|
||||
/**
|
||||
* @return The current custom view.
|
||||
*/
|
||||
public abstract View getCustomView();
|
||||
|
||||
/**
|
||||
* Returns the current ActionBar title in standard mode.
|
||||
* Returns null if {@link #getNavigationMode()} would not return
|
||||
* {@link #NAVIGATION_MODE_STANDARD}.
|
||||
*
|
||||
* @return The current ActionBar title or null.
|
||||
*/
|
||||
public abstract CharSequence getTitle();
|
||||
|
||||
/**
|
||||
* Returns the current ActionBar subtitle in standard mode.
|
||||
* Returns null if {@link #getNavigationMode()} would not return
|
||||
* {@link #NAVIGATION_MODE_STANDARD}.
|
||||
*
|
||||
* @return The current ActionBar subtitle or null.
|
||||
*/
|
||||
public abstract CharSequence getSubtitle();
|
||||
|
||||
/**
|
||||
* Returns the current navigation mode. The result will be one of:
|
||||
* <ul>
|
||||
* <li>{@link #NAVIGATION_MODE_STANDARD}</li>
|
||||
* <li>{@link #NAVIGATION_MODE_LIST}</li>
|
||||
* <li>{@link #NAVIGATION_MODE_TABS}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @return The current navigation mode.
|
||||
*/
|
||||
public abstract int getNavigationMode();
|
||||
|
||||
/**
|
||||
* Set the current navigation mode.
|
||||
*
|
||||
* @param mode The new mode to set.
|
||||
* @see #NAVIGATION_MODE_STANDARD
|
||||
* @see #NAVIGATION_MODE_LIST
|
||||
* @see #NAVIGATION_MODE_TABS
|
||||
*/
|
||||
public abstract void setNavigationMode(int mode);
|
||||
|
||||
/**
|
||||
* @return The current set of display options.
|
||||
*/
|
||||
public abstract int getDisplayOptions();
|
||||
|
||||
/**
|
||||
* Create and return a new {@link Tab}.
|
||||
* This tab will not be included in the action bar until it is added.
|
||||
*
|
||||
* <p>Very often tabs will be used to switch between {@link Fragment}
|
||||
* objects. Here is a typical implementation of such tabs:</p>
|
||||
*
|
||||
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentTabs.java
|
||||
* complete}
|
||||
*
|
||||
* @return A new Tab
|
||||
*
|
||||
* @see #addTab(Tab)
|
||||
*/
|
||||
public abstract Tab newTab();
|
||||
|
||||
/**
|
||||
* Add a tab for use in tabbed navigation mode. The tab will be added at the end of the list.
|
||||
* If this is the first tab to be added it will become the selected tab.
|
||||
*
|
||||
* @param tab Tab to add
|
||||
*/
|
||||
public abstract void addTab(Tab tab);
|
||||
|
||||
/**
|
||||
* Add a tab for use in tabbed navigation mode. The tab will be added at the end of the list.
|
||||
*
|
||||
* @param tab Tab to add
|
||||
* @param setSelected True if the added tab should become the selected tab.
|
||||
*/
|
||||
public abstract void addTab(Tab tab, boolean setSelected);
|
||||
|
||||
/**
|
||||
* Add a tab for use in tabbed navigation mode. The tab will be inserted at
|
||||
* <code>position</code>. If this is the first tab to be added it will become
|
||||
* the selected tab.
|
||||
*
|
||||
* @param tab The tab to add
|
||||
* @param position The new position of the tab
|
||||
*/
|
||||
public abstract void addTab(Tab tab, int position);
|
||||
|
||||
/**
|
||||
* Add a tab for use in tabbed navigation mode. The tab will be insterted at
|
||||
* <code>position</code>.
|
||||
*
|
||||
* @param tab The tab to add
|
||||
* @param position The new position of the tab
|
||||
* @param setSelected True if the added tab should become the selected tab.
|
||||
*/
|
||||
public abstract void addTab(Tab tab, int position, boolean setSelected);
|
||||
|
||||
/**
|
||||
* Remove a tab from the action bar. If the removed tab was selected it will be deselected
|
||||
* and another tab will be selected if present.
|
||||
*
|
||||
* @param tab The tab to remove
|
||||
*/
|
||||
public abstract void removeTab(Tab tab);
|
||||
|
||||
/**
|
||||
* Remove a tab from the action bar. If the removed tab was selected it will be deselected
|
||||
* and another tab will be selected if present.
|
||||
*
|
||||
* @param position Position of the tab to remove
|
||||
*/
|
||||
public abstract void removeTabAt(int position);
|
||||
|
||||
/**
|
||||
* Remove all tabs from the action bar and deselect the current tab.
|
||||
*/
|
||||
public abstract void removeAllTabs();
|
||||
|
||||
/**
|
||||
* Select the specified tab. If it is not a child of this action bar it will be added.
|
||||
*
|
||||
* <p>Note: If you want to select by index, use {@link #setSelectedNavigationItem(int)}.</p>
|
||||
*
|
||||
* @param tab Tab to select
|
||||
*/
|
||||
public abstract void selectTab(Tab tab);
|
||||
|
||||
/**
|
||||
* Returns the currently selected tab if in tabbed navigation mode and there is at least
|
||||
* one tab present.
|
||||
*
|
||||
* @return The currently selected tab or null
|
||||
*/
|
||||
public abstract Tab getSelectedTab();
|
||||
|
||||
/**
|
||||
* Returns the tab at the specified index.
|
||||
*
|
||||
* @param index Index value in the range 0-get
|
||||
* @return
|
||||
*/
|
||||
public abstract Tab getTabAt(int index);
|
||||
|
||||
/**
|
||||
* Returns the number of tabs currently registered with the action bar.
|
||||
* @return Tab count
|
||||
*/
|
||||
public abstract int getTabCount();
|
||||
|
||||
/**
|
||||
* Retrieve the current height of the ActionBar.
|
||||
*
|
||||
* @return The ActionBar's height
|
||||
*/
|
||||
public abstract int getHeight();
|
||||
|
||||
/**
|
||||
* Show the ActionBar if it is not currently showing.
|
||||
* If the window hosting the ActionBar does not have the feature
|
||||
* {@link Window#FEATURE_ACTION_BAR_OVERLAY} it will resize application
|
||||
* content to fit the new space available.
|
||||
*/
|
||||
public abstract void show();
|
||||
|
||||
/**
|
||||
* Hide the ActionBar if it is currently showing.
|
||||
* If the window hosting the ActionBar does not have the feature
|
||||
* {@link Window#FEATURE_ACTION_BAR_OVERLAY} it will resize application
|
||||
* content to fit the new space available.
|
||||
*/
|
||||
public abstract void hide();
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the ActionBar is showing, <code>false</code> otherwise.
|
||||
*/
|
||||
public abstract boolean isShowing();
|
||||
|
||||
/**
|
||||
* Add a listener that will respond to menu visibility change events.
|
||||
*
|
||||
* @param listener The new listener to add
|
||||
*/
|
||||
public abstract void addOnMenuVisibilityListener(OnMenuVisibilityListener listener);
|
||||
|
||||
/**
|
||||
* Remove a menu visibility listener. This listener will no longer receive menu
|
||||
* visibility change events.
|
||||
*
|
||||
* @param listener A listener to remove that was previously added
|
||||
*/
|
||||
public abstract void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener);
|
||||
|
||||
/**
|
||||
* Enable or disable the "home" button in the corner of the action bar. (Note that this
|
||||
* is the application home/up affordance on the action bar, not the systemwide home
|
||||
* button.)
|
||||
*
|
||||
* <p>This defaults to true for packages targeting < API 14. For packages targeting
|
||||
* API 14 or greater, the application should call this method to enable interaction
|
||||
* with the home/up affordance.
|
||||
*
|
||||
* <p>Setting the {@link #DISPLAY_HOME_AS_UP} display option will automatically enable
|
||||
* the home button.
|
||||
*
|
||||
* @param enabled true to enable the home button, false to disable the home button.
|
||||
*/
|
||||
public void setHomeButtonEnabled(boolean enabled) { }
|
||||
|
||||
/**
|
||||
* Returns a {@link Context} with an appropriate theme for creating views that
|
||||
* will appear in the action bar. If you are inflating or instantiating custom views
|
||||
* that will appear in an action bar, you should use the Context returned by this method.
|
||||
* (This includes adapters used for list navigation mode.)
|
||||
* This will ensure that views contrast properly against the action bar.
|
||||
*
|
||||
* @return A themed Context for creating views
|
||||
*/
|
||||
public Context getThemedContext() { return null; }
|
||||
|
||||
/**
|
||||
* Listener interface for ActionBar navigation events.
|
||||
*/
|
||||
public interface OnNavigationListener {
|
||||
/**
|
||||
* This method is called whenever a navigation item in your action bar
|
||||
* is selected.
|
||||
*
|
||||
* @param itemPosition Position of the item clicked.
|
||||
* @param itemId ID of the item clicked.
|
||||
* @return True if the event was handled, false otherwise.
|
||||
*/
|
||||
public boolean onNavigationItemSelected(int itemPosition, long itemId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for receiving events when action bar menus are shown or hidden.
|
||||
*/
|
||||
public interface OnMenuVisibilityListener {
|
||||
/**
|
||||
* Called when an action bar menu is shown or hidden. Applications may want to use
|
||||
* this to tune auto-hiding behavior for the action bar or pause/resume video playback,
|
||||
* gameplay, or other activity within the main content area.
|
||||
*
|
||||
* @param isVisible True if an action bar menu is now visible, false if no action bar
|
||||
* menus are visible.
|
||||
*/
|
||||
public void onMenuVisibilityChanged(boolean isVisible);
|
||||
}
|
||||
|
||||
/**
|
||||
* A tab in the action bar.
|
||||
*
|
||||
* <p>Tabs manage the hiding and showing of {@link Fragment}s.
|
||||
*/
|
||||
public static abstract class Tab {
|
||||
/**
|
||||
* An invalid position for a tab.
|
||||
*
|
||||
* @see #getPosition()
|
||||
*/
|
||||
public static final int INVALID_POSITION = -1;
|
||||
|
||||
/**
|
||||
* Return the current position of this tab in the action bar.
|
||||
*
|
||||
* @return Current position, or {@link #INVALID_POSITION} if this tab is not currently in
|
||||
* the action bar.
|
||||
*/
|
||||
public abstract int getPosition();
|
||||
|
||||
/**
|
||||
* Return the icon associated with this tab.
|
||||
*
|
||||
* @return The tab's icon
|
||||
*/
|
||||
public abstract Drawable getIcon();
|
||||
|
||||
/**
|
||||
* Return the text of this tab.
|
||||
*
|
||||
* @return The tab's text
|
||||
*/
|
||||
public abstract CharSequence getText();
|
||||
|
||||
/**
|
||||
* Set the icon displayed on this tab.
|
||||
*
|
||||
* @param icon The drawable to use as an icon
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setIcon(Drawable icon);
|
||||
|
||||
/**
|
||||
* Set the icon displayed on this tab.
|
||||
*
|
||||
* @param resId Resource ID referring to the drawable to use as an icon
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setIcon(int resId);
|
||||
|
||||
/**
|
||||
* Set the text displayed on this tab. Text may be truncated if there is not
|
||||
* room to display the entire string.
|
||||
*
|
||||
* @param text The text to display
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setText(CharSequence text);
|
||||
|
||||
/**
|
||||
* Set the text displayed on this tab. Text may be truncated if there is not
|
||||
* room to display the entire string.
|
||||
*
|
||||
* @param resId A resource ID referring to the text that should be displayed
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setText(int resId);
|
||||
|
||||
/**
|
||||
* Set a custom view to be used for this tab. This overrides values set by
|
||||
* {@link #setText(CharSequence)} and {@link #setIcon(Drawable)}.
|
||||
*
|
||||
* @param view Custom view to be used as a tab.
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setCustomView(View view);
|
||||
|
||||
/**
|
||||
* Set a custom view to be used for this tab. This overrides values set by
|
||||
* {@link #setText(CharSequence)} and {@link #setIcon(Drawable)}.
|
||||
*
|
||||
* @param layoutResId A layout resource to inflate and use as a custom tab view
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setCustomView(int layoutResId);
|
||||
|
||||
/**
|
||||
* Retrieve a previously set custom view for this tab.
|
||||
*
|
||||
* @return The custom view set by {@link #setCustomView(View)}.
|
||||
*/
|
||||
public abstract View getCustomView();
|
||||
|
||||
/**
|
||||
* Give this Tab an arbitrary object to hold for later use.
|
||||
*
|
||||
* @param obj Object to store
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setTag(Object obj);
|
||||
|
||||
/**
|
||||
* @return This Tab's tag object.
|
||||
*/
|
||||
public abstract Object getTag();
|
||||
|
||||
/**
|
||||
* Set the {@link TabListener} that will handle switching to and from this tab.
|
||||
* All tabs must have a TabListener set before being added to the ActionBar.
|
||||
*
|
||||
* @param listener Listener to handle tab selection events
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setTabListener(TabListener listener);
|
||||
|
||||
/**
|
||||
* Select this tab. Only valid if the tab has been added to the action bar.
|
||||
*/
|
||||
public abstract void select();
|
||||
|
||||
/**
|
||||
* Set a description of this tab's content for use in accessibility support.
|
||||
* If no content description is provided the title will be used.
|
||||
*
|
||||
* @param resId A resource ID referring to the description text
|
||||
* @return The current instance for call chaining
|
||||
* @see #setContentDescription(CharSequence)
|
||||
* @see #getContentDescription()
|
||||
*/
|
||||
public abstract Tab setContentDescription(int resId);
|
||||
|
||||
/**
|
||||
* Set a description of this tab's content for use in accessibility support.
|
||||
* If no content description is provided the title will be used.
|
||||
*
|
||||
* @param contentDesc Description of this tab's content
|
||||
* @return The current instance for call chaining
|
||||
* @see #setContentDescription(int)
|
||||
* @see #getContentDescription()
|
||||
*/
|
||||
public abstract Tab setContentDescription(CharSequence contentDesc);
|
||||
|
||||
/**
|
||||
* Gets a brief description of this tab's content for use in accessibility support.
|
||||
*
|
||||
* @return Description of this tab's content
|
||||
* @see #setContentDescription(CharSequence)
|
||||
* @see #setContentDescription(int)
|
||||
*/
|
||||
public abstract CharSequence getContentDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface invoked when a tab is focused, unfocused, added, or removed.
|
||||
*/
|
||||
public interface TabListener {
|
||||
/**
|
||||
* Called when a tab enters the selected state.
|
||||
*
|
||||
* @param tab The tab that was selected
|
||||
* @param ft A {@link FragmentTransaction} for queuing fragment operations to execute
|
||||
* during a tab switch. The previous tab's unselect and this tab's select will be
|
||||
* executed in a single transaction. This FragmentTransaction does not support
|
||||
* being added to the back stack.
|
||||
*/
|
||||
public void onTabSelected(Tab tab, FragmentTransaction ft);
|
||||
|
||||
/**
|
||||
* Called when a tab exits the selected state.
|
||||
*
|
||||
* @param tab The tab that was unselected
|
||||
* @param ft A {@link FragmentTransaction} for queuing fragment operations to execute
|
||||
* during a tab switch. This tab's unselect and the newly selected tab's select
|
||||
* will be executed in a single transaction. This FragmentTransaction does not
|
||||
* support being added to the back stack.
|
||||
*/
|
||||
public void onTabUnselected(Tab tab, FragmentTransaction ft);
|
||||
|
||||
/**
|
||||
* Called when a tab that is already selected is chosen again by the user.
|
||||
* Some applications may use this action to return to the top level of a category.
|
||||
*
|
||||
* @param tab The tab that was reselected.
|
||||
* @param ft A {@link FragmentTransaction} for queuing fragment operations to execute
|
||||
* once this method returns. This FragmentTransaction does not support
|
||||
* being added to the back stack.
|
||||
*/
|
||||
public void onTabReselected(Tab tab, FragmentTransaction ft);
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-child layout information associated with action bar custom views.
|
||||
*
|
||||
* @attr ref android.R.styleable#ActionBar_LayoutParams_layout_gravity
|
||||
*/
|
||||
public static class LayoutParams extends MarginLayoutParams {
|
||||
private static final int[] ATTRS = new int[] {
|
||||
android.R.attr.layout_gravity
|
||||
};
|
||||
|
||||
/**
|
||||
* Gravity for the view associated with these LayoutParams.
|
||||
*
|
||||
* @see android.view.Gravity
|
||||
*/
|
||||
@ViewDebug.ExportedProperty(mapping = {
|
||||
@ViewDebug.IntToString(from = -1, to = "NONE"),
|
||||
@ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"),
|
||||
@ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"),
|
||||
@ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"),
|
||||
@ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"),
|
||||
@ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"),
|
||||
@ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"),
|
||||
@ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"),
|
||||
@ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
|
||||
@ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"),
|
||||
@ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"),
|
||||
@ViewDebug.IntToString(from = Gravity.FILL, to = "FILL")
|
||||
})
|
||||
public int gravity = -1;
|
||||
|
||||
public LayoutParams(Context c, AttributeSet attrs) {
|
||||
super(c, attrs);
|
||||
|
||||
TypedArray a = c.obtainStyledAttributes(attrs, ATTRS);
|
||||
gravity = a.getInt(0, -1);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public LayoutParams(int width, int height) {
|
||||
super(width, height);
|
||||
this.gravity = Gravity.CENTER_VERTICAL | Gravity.LEFT;
|
||||
}
|
||||
|
||||
public LayoutParams(int width, int height, int gravity) {
|
||||
super(width, height);
|
||||
this.gravity = gravity;
|
||||
}
|
||||
|
||||
public LayoutParams(int gravity) {
|
||||
this(WRAP_CONTENT, FILL_PARENT, gravity);
|
||||
}
|
||||
|
||||
public LayoutParams(LayoutParams source) {
|
||||
super(source);
|
||||
|
||||
this.gravity = source.gravity;
|
||||
}
|
||||
|
||||
public LayoutParams(ViewGroup.LayoutParams source) {
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,270 +0,0 @@
|
||||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import com.actionbarsherlock.ActionBarSherlock;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
public abstract class SherlockActivity extends Activity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener {
|
||||
private ActionBarSherlock mSherlock;
|
||||
|
||||
protected final ActionBarSherlock getSherlock() {
|
||||
if (mSherlock == null) {
|
||||
mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE);
|
||||
}
|
||||
return mSherlock;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Action bar and mode
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public ActionBar getSupportActionBar() {
|
||||
return getSherlock().getActionBar();
|
||||
}
|
||||
|
||||
public ActionMode startActionMode(ActionMode.Callback callback) {
|
||||
return getSherlock().startActionMode(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionModeStarted(ActionMode mode) {}
|
||||
|
||||
@Override
|
||||
public void onActionModeFinished(ActionMode mode) {}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// General lifecycle/callback dispatching
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
getSherlock().dispatchConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostResume() {
|
||||
super.onPostResume();
|
||||
getSherlock().dispatchPostResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
getSherlock().dispatchPause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
getSherlock().dispatchStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
getSherlock().dispatchDestroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
getSherlock().dispatchPostCreate(savedInstanceState);
|
||||
super.onPostCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTitleChanged(CharSequence title, int color) {
|
||||
getSherlock().dispatchTitleChanged(title, color);
|
||||
super.onTitleChanged(title, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onMenuOpened(int featureId, android.view.Menu menu) {
|
||||
if (getSherlock().dispatchMenuOpened(featureId, menu)) {
|
||||
return true;
|
||||
}
|
||||
return super.onMenuOpened(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelClosed(int featureId, android.view.Menu menu) {
|
||||
getSherlock().dispatchPanelClosed(featureId, menu);
|
||||
super.onPanelClosed(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (getSherlock().dispatchKeyEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
getSherlock().dispatchSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
getSherlock().dispatchRestoreInstanceState(savedInstanceState);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Native menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public MenuInflater getSupportMenuInflater() {
|
||||
return getSherlock().getMenuInflater();
|
||||
}
|
||||
|
||||
public void invalidateOptionsMenu() {
|
||||
getSherlock().dispatchInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
public void supportInvalidateOptionsMenu() {
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onCreateOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return getSherlock().dispatchOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openOptionsMenu() {
|
||||
if (!getSherlock().dispatchOpenOptionsMenu()) {
|
||||
super.openOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOptionsMenu() {
|
||||
if (!getSherlock().dispatchCloseOptionsMenu()) {
|
||||
super.closeOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Sherlock menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public boolean onCreatePanelMenu(int featureId, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onCreateOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreparePanel(int featureId, View view, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onPrepareOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onOptionsItemSelected(item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Content
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void addContentView(View view, LayoutParams params) {
|
||||
getSherlock().addContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(int layoutResId) {
|
||||
getSherlock().setContentView(layoutResId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view, LayoutParams params) {
|
||||
getSherlock().setContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view) {
|
||||
getSherlock().setContentView(view);
|
||||
}
|
||||
|
||||
public void requestWindowFeature(long featureId) {
|
||||
getSherlock().requestFeature((int)featureId);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Progress Indication
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setSupportProgress(int progress) {
|
||||
getSherlock().setProgress(progress);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminate(boolean indeterminate) {
|
||||
getSherlock().setProgressBarIndeterminate(indeterminate);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminateVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarIndeterminateVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportSecondaryProgress(int secondaryProgress) {
|
||||
getSherlock().setSecondaryProgress(secondaryProgress);
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuItemWrapper;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuWrapper;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
import static com.actionbarsherlock.app.SherlockFragmentActivity.OnCreateOptionsMenuListener;
|
||||
import static com.actionbarsherlock.app.SherlockFragmentActivity.OnOptionsItemSelectedListener;
|
||||
import static com.actionbarsherlock.app.SherlockFragmentActivity.OnPrepareOptionsMenuListener;
|
||||
|
||||
public class SherlockDialogFragment extends DialogFragment implements OnCreateOptionsMenuListener, OnPrepareOptionsMenuListener, OnOptionsItemSelectedListener {
|
||||
private SherlockFragmentActivity mActivity;
|
||||
|
||||
public SherlockFragmentActivity getSherlockActivity() {
|
||||
return mActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
if (!(activity instanceof SherlockFragmentActivity)) {
|
||||
throw new IllegalStateException(getClass().getSimpleName() + " must be attached to a SherlockFragmentActivity.");
|
||||
}
|
||||
mActivity = (SherlockFragmentActivity)activity;
|
||||
|
||||
super.onAttach(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
mActivity = null;
|
||||
super.onDetach();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) {
|
||||
onCreateOptionsMenu(new MenuWrapper(menu), mActivity.getSupportMenuInflater());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
//Nothing to see here.
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
onPrepareOptionsMenu(new MenuWrapper(menu));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
//Nothing to see here.
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return onOptionsItemSelected(new MenuItemWrapper(item));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
//Nothing to see here.
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,259 +0,0 @@
|
||||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.app.ExpandableListActivity;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.view.Window;
|
||||
import com.actionbarsherlock.ActionBarSherlock;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
public abstract class SherlockExpandableListActivity extends ExpandableListActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener {
|
||||
private ActionBarSherlock mSherlock;
|
||||
|
||||
protected final ActionBarSherlock getSherlock() {
|
||||
if (mSherlock == null) {
|
||||
mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE);
|
||||
}
|
||||
return mSherlock;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Action bar and mode
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public ActionBar getSupportActionBar() {
|
||||
return getSherlock().getActionBar();
|
||||
}
|
||||
|
||||
public ActionMode startActionMode(ActionMode.Callback callback) {
|
||||
return getSherlock().startActionMode(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionModeStarted(ActionMode mode) {}
|
||||
|
||||
@Override
|
||||
public void onActionModeFinished(ActionMode mode) {}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// General lifecycle/callback dispatching
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
getSherlock().dispatchConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostResume() {
|
||||
super.onPostResume();
|
||||
getSherlock().dispatchPostResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
getSherlock().dispatchPause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
getSherlock().dispatchStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
getSherlock().dispatchDestroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
getSherlock().dispatchPostCreate(savedInstanceState);
|
||||
super.onPostCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTitleChanged(CharSequence title, int color) {
|
||||
getSherlock().dispatchTitleChanged(title, color);
|
||||
super.onTitleChanged(title, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onMenuOpened(int featureId, android.view.Menu menu) {
|
||||
if (getSherlock().dispatchMenuOpened(featureId, menu)) {
|
||||
return true;
|
||||
}
|
||||
return super.onMenuOpened(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelClosed(int featureId, android.view.Menu menu) {
|
||||
getSherlock().dispatchPanelClosed(featureId, menu);
|
||||
super.onPanelClosed(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (getSherlock().dispatchKeyEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Native menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public MenuInflater getSupportMenuInflater() {
|
||||
return getSherlock().getMenuInflater();
|
||||
}
|
||||
|
||||
public void invalidateOptionsMenu() {
|
||||
getSherlock().dispatchInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
public void supportInvalidateOptionsMenu() {
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onCreateOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return getSherlock().dispatchOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openOptionsMenu() {
|
||||
if (!getSherlock().dispatchOpenOptionsMenu()) {
|
||||
super.openOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOptionsMenu() {
|
||||
if (!getSherlock().dispatchCloseOptionsMenu()) {
|
||||
super.closeOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Sherlock menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public boolean onCreatePanelMenu(int featureId, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onCreateOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreparePanel(int featureId, View view, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onPrepareOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onOptionsItemSelected(item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Content
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void addContentView(View view, LayoutParams params) {
|
||||
getSherlock().addContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(int layoutResId) {
|
||||
getSherlock().setContentView(layoutResId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view, LayoutParams params) {
|
||||
getSherlock().setContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view) {
|
||||
getSherlock().setContentView(view);
|
||||
}
|
||||
|
||||
public void requestWindowFeature(long featureId) {
|
||||
getSherlock().requestFeature((int)featureId);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Progress Indication
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setSupportProgress(int progress) {
|
||||
getSherlock().setProgress(progress);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminate(boolean indeterminate) {
|
||||
getSherlock().setProgressBarIndeterminate(indeterminate);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminateVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarIndeterminateVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportSecondaryProgress(int secondaryProgress) {
|
||||
getSherlock().setSecondaryProgress(secondaryProgress);
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.v4.app.Fragment;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuItemWrapper;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuWrapper;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
import static com.actionbarsherlock.app.SherlockFragmentActivity.OnCreateOptionsMenuListener;
|
||||
import static com.actionbarsherlock.app.SherlockFragmentActivity.OnOptionsItemSelectedListener;
|
||||
import static com.actionbarsherlock.app.SherlockFragmentActivity.OnPrepareOptionsMenuListener;
|
||||
|
||||
public class SherlockFragment extends Fragment implements OnCreateOptionsMenuListener, OnPrepareOptionsMenuListener, OnOptionsItemSelectedListener {
|
||||
private SherlockFragmentActivity mActivity;
|
||||
|
||||
public SherlockFragmentActivity getSherlockActivity() {
|
||||
return mActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
if (!(activity instanceof SherlockFragmentActivity)) {
|
||||
throw new IllegalStateException(getClass().getSimpleName() + " must be attached to a SherlockFragmentActivity.");
|
||||
}
|
||||
mActivity = (SherlockFragmentActivity)activity;
|
||||
|
||||
super.onAttach(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
mActivity = null;
|
||||
super.onDetach();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) {
|
||||
onCreateOptionsMenu(new MenuWrapper(menu), mActivity.getSupportMenuInflater());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
//Nothing to see here.
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
onPrepareOptionsMenu(new MenuWrapper(menu));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
//Nothing to see here.
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return onOptionsItemSelected(new MenuItemWrapper(item));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
//Nothing to see here.
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,303 +0,0 @@
|
||||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Watson;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.view.Window;
|
||||
import com.actionbarsherlock.ActionBarSherlock;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
import static com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener;
|
||||
import static com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener;
|
||||
|
||||
/** @see {@link android.support.v4.app.Watson} */
|
||||
public class SherlockFragmentActivity extends Watson implements OnActionModeStartedListener, OnActionModeFinishedListener {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "SherlockFragmentActivity";
|
||||
|
||||
private ActionBarSherlock mSherlock;
|
||||
private boolean mIgnoreNativeCreate = false;
|
||||
private boolean mIgnoreNativePrepare = false;
|
||||
private boolean mIgnoreNativeSelected = false;
|
||||
|
||||
protected final ActionBarSherlock getSherlock() {
|
||||
if (mSherlock == null) {
|
||||
mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE);
|
||||
}
|
||||
return mSherlock;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Action bar and mode
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public ActionBar getSupportActionBar() {
|
||||
return getSherlock().getActionBar();
|
||||
}
|
||||
|
||||
public ActionMode startActionMode(ActionMode.Callback callback) {
|
||||
return getSherlock().startActionMode(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionModeStarted(ActionMode mode) {}
|
||||
|
||||
@Override
|
||||
public void onActionModeFinished(ActionMode mode) {}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// General lifecycle/callback dispatching
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
getSherlock().dispatchConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostResume() {
|
||||
super.onPostResume();
|
||||
getSherlock().dispatchPostResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
getSherlock().dispatchPause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
getSherlock().dispatchStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
getSherlock().dispatchDestroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
getSherlock().dispatchPostCreate(savedInstanceState);
|
||||
super.onPostCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTitleChanged(CharSequence title, int color) {
|
||||
getSherlock().dispatchTitleChanged(title, color);
|
||||
super.onTitleChanged(title, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onMenuOpened(int featureId, android.view.Menu menu) {
|
||||
if (getSherlock().dispatchMenuOpened(featureId, menu)) {
|
||||
return true;
|
||||
}
|
||||
return super.onMenuOpened(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelClosed(int featureId, android.view.Menu menu) {
|
||||
getSherlock().dispatchPanelClosed(featureId, menu);
|
||||
super.onPanelClosed(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (getSherlock().dispatchKeyEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
getSherlock().dispatchSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
getSherlock().dispatchRestoreInstanceState(savedInstanceState);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Native menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public MenuInflater getSupportMenuInflater() {
|
||||
if (DEBUG) Log.d(TAG, "[getSupportMenuInflater]");
|
||||
|
||||
return getSherlock().getMenuInflater();
|
||||
}
|
||||
|
||||
public void invalidateOptionsMenu() {
|
||||
if (DEBUG) Log.d(TAG, "[invalidateOptionsMenu]");
|
||||
|
||||
getSherlock().dispatchInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
public void supportInvalidateOptionsMenu() {
|
||||
if (DEBUG) Log.d(TAG, "[supportInvalidateOptionsMenu]");
|
||||
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onCreatePanelMenu(int featureId, android.view.Menu menu) {
|
||||
if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] featureId: " + featureId + ", menu: " + menu);
|
||||
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL && !mIgnoreNativeCreate) {
|
||||
mIgnoreNativeCreate = true;
|
||||
boolean result = getSherlock().dispatchCreateOptionsMenu(menu);
|
||||
mIgnoreNativeCreate = false;
|
||||
|
||||
if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] returning " + result);
|
||||
return result;
|
||||
}
|
||||
return super.onCreatePanelMenu(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onCreateOptionsMenu(android.view.Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onPreparePanel(int featureId, View view, android.view.Menu menu) {
|
||||
if (DEBUG) Log.d(TAG, "[onPreparePanel] featureId: " + featureId + ", view: " + view + ", menu: " + menu);
|
||||
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL && !mIgnoreNativePrepare) {
|
||||
mIgnoreNativePrepare = true;
|
||||
boolean result = getSherlock().dispatchPrepareOptionsMenu(menu);
|
||||
mIgnoreNativePrepare = false;
|
||||
|
||||
if (DEBUG) Log.d(TAG, "[onPreparePanel] returning " + result);
|
||||
return result;
|
||||
}
|
||||
return super.onPreparePanel(featureId, view, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onMenuItemSelected(int featureId, android.view.MenuItem item) {
|
||||
if (DEBUG) Log.d(TAG, "[onMenuItemSelected] featureId: " + featureId + ", item: " + item);
|
||||
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL && !mIgnoreNativeSelected) {
|
||||
mIgnoreNativeSelected = true;
|
||||
boolean result = getSherlock().dispatchOptionsItemSelected(item);
|
||||
mIgnoreNativeSelected = false;
|
||||
|
||||
if (DEBUG) Log.d(TAG, "[onMenuItemSelected] returning " + result);
|
||||
return result;
|
||||
}
|
||||
return super.onMenuItemSelected(featureId, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openOptionsMenu() {
|
||||
if (!getSherlock().dispatchOpenOptionsMenu()) {
|
||||
super.openOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOptionsMenu() {
|
||||
if (!getSherlock().dispatchCloseOptionsMenu()) {
|
||||
super.closeOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Sherlock menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Content
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void addContentView(View view, LayoutParams params) {
|
||||
getSherlock().addContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(int layoutResId) {
|
||||
getSherlock().setContentView(layoutResId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view, LayoutParams params) {
|
||||
getSherlock().setContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view) {
|
||||
getSherlock().setContentView(view);
|
||||
}
|
||||
|
||||
public void requestWindowFeature(long featureId) {
|
||||
getSherlock().requestFeature((int)featureId);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Progress Indication
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setSupportProgress(int progress) {
|
||||
getSherlock().setProgress(progress);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminate(boolean indeterminate) {
|
||||
getSherlock().setProgressBarIndeterminate(indeterminate);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminateVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarIndeterminateVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportSecondaryProgress(int secondaryProgress) {
|
||||
getSherlock().setSecondaryProgress(secondaryProgress);
|
||||
}
|
||||
}
|
@ -1,270 +0,0 @@
|
||||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import com.actionbarsherlock.ActionBarSherlock;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
public abstract class SherlockListActivity extends ListActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener {
|
||||
private ActionBarSherlock mSherlock;
|
||||
|
||||
protected final ActionBarSherlock getSherlock() {
|
||||
if (mSherlock == null) {
|
||||
mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE);
|
||||
}
|
||||
return mSherlock;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Action bar and mode
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public ActionBar getSupportActionBar() {
|
||||
return getSherlock().getActionBar();
|
||||
}
|
||||
|
||||
public ActionMode startActionMode(ActionMode.Callback callback) {
|
||||
return getSherlock().startActionMode(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionModeStarted(ActionMode mode) {}
|
||||
|
||||
@Override
|
||||
public void onActionModeFinished(ActionMode mode) {}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// General lifecycle/callback dispatching
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
getSherlock().dispatchConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostResume() {
|
||||
super.onPostResume();
|
||||
getSherlock().dispatchPostResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
getSherlock().dispatchPause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
getSherlock().dispatchStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
getSherlock().dispatchDestroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
getSherlock().dispatchPostCreate(savedInstanceState);
|
||||
super.onPostCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTitleChanged(CharSequence title, int color) {
|
||||
getSherlock().dispatchTitleChanged(title, color);
|
||||
super.onTitleChanged(title, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onMenuOpened(int featureId, android.view.Menu menu) {
|
||||
if (getSherlock().dispatchMenuOpened(featureId, menu)) {
|
||||
return true;
|
||||
}
|
||||
return super.onMenuOpened(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelClosed(int featureId, android.view.Menu menu) {
|
||||
getSherlock().dispatchPanelClosed(featureId, menu);
|
||||
super.onPanelClosed(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (getSherlock().dispatchKeyEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
getSherlock().dispatchSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
getSherlock().dispatchRestoreInstanceState(savedInstanceState);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Native menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public MenuInflater getSupportMenuInflater() {
|
||||
return getSherlock().getMenuInflater();
|
||||
}
|
||||
|
||||
public void invalidateOptionsMenu() {
|
||||
getSherlock().dispatchInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
public void supportInvalidateOptionsMenu() {
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onCreateOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return getSherlock().dispatchOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openOptionsMenu() {
|
||||
if (!getSherlock().dispatchOpenOptionsMenu()) {
|
||||
super.openOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOptionsMenu() {
|
||||
if (!getSherlock().dispatchCloseOptionsMenu()) {
|
||||
super.closeOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Sherlock menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public boolean onCreatePanelMenu(int featureId, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onCreateOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreparePanel(int featureId, View view, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onPrepareOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onOptionsItemSelected(item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Content
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void addContentView(View view, LayoutParams params) {
|
||||
getSherlock().addContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(int layoutResId) {
|
||||
getSherlock().setContentView(layoutResId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view, LayoutParams params) {
|
||||
getSherlock().setContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view) {
|
||||
getSherlock().setContentView(view);
|
||||
}
|
||||
|
||||
public void requestWindowFeature(long featureId) {
|
||||
getSherlock().requestFeature((int)featureId);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Progress Indication
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setSupportProgress(int progress) {
|
||||
getSherlock().setProgress(progress);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminate(boolean indeterminate) {
|
||||
getSherlock().setProgressBarIndeterminate(indeterminate);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminateVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarIndeterminateVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportSecondaryProgress(int secondaryProgress) {
|
||||
getSherlock().setSecondaryProgress(secondaryProgress);
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuItemWrapper;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuWrapper;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
import static com.actionbarsherlock.app.SherlockFragmentActivity.OnCreateOptionsMenuListener;
|
||||
import static com.actionbarsherlock.app.SherlockFragmentActivity.OnOptionsItemSelectedListener;
|
||||
import static com.actionbarsherlock.app.SherlockFragmentActivity.OnPrepareOptionsMenuListener;
|
||||
|
||||
public class SherlockListFragment extends ListFragment implements OnCreateOptionsMenuListener, OnPrepareOptionsMenuListener, OnOptionsItemSelectedListener {
|
||||
private SherlockFragmentActivity mActivity;
|
||||
|
||||
public SherlockFragmentActivity getSherlockActivity() {
|
||||
return mActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
if (!(activity instanceof SherlockFragmentActivity)) {
|
||||
throw new IllegalStateException(getClass().getSimpleName() + " must be attached to a SherlockFragmentActivity.");
|
||||
}
|
||||
mActivity = (SherlockFragmentActivity)activity;
|
||||
|
||||
super.onAttach(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
mActivity = null;
|
||||
super.onDetach();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) {
|
||||
onCreateOptionsMenu(new MenuWrapper(menu), mActivity.getSupportMenuInflater());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
//Nothing to see here.
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
onPrepareOptionsMenu(new MenuWrapper(menu));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
//Nothing to see here.
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return onOptionsItemSelected(new MenuItemWrapper(item));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onContextItemSelected(android.view.MenuItem item) {
|
||||
return onContextItemSelected(new MenuItemWrapper(item));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
//Nothing to see here.
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
//Nothing to see here.
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,270 +0,0 @@
|
||||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.view.Window;
|
||||
import com.actionbarsherlock.ActionBarSherlock;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
public abstract class SherlockPreferenceActivity extends PreferenceActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener {
|
||||
private ActionBarSherlock mSherlock;
|
||||
|
||||
protected final ActionBarSherlock getSherlock() {
|
||||
if (mSherlock == null) {
|
||||
mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE);
|
||||
}
|
||||
return mSherlock;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Action bar and mode
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public ActionBar getSupportActionBar() {
|
||||
return getSherlock().getActionBar();
|
||||
}
|
||||
|
||||
public ActionMode startActionMode(ActionMode.Callback callback) {
|
||||
return getSherlock().startActionMode(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionModeStarted(ActionMode mode) {}
|
||||
|
||||
@Override
|
||||
public void onActionModeFinished(ActionMode mode) {}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// General lifecycle/callback dispatching
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
getSherlock().dispatchConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostResume() {
|
||||
super.onPostResume();
|
||||
getSherlock().dispatchPostResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
getSherlock().dispatchPause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
getSherlock().dispatchStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
getSherlock().dispatchDestroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
getSherlock().dispatchPostCreate(savedInstanceState);
|
||||
super.onPostCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTitleChanged(CharSequence title, int color) {
|
||||
getSherlock().dispatchTitleChanged(title, color);
|
||||
super.onTitleChanged(title, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onMenuOpened(int featureId, android.view.Menu menu) {
|
||||
if (getSherlock().dispatchMenuOpened(featureId, menu)) {
|
||||
return true;
|
||||
}
|
||||
return super.onMenuOpened(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelClosed(int featureId, android.view.Menu menu) {
|
||||
getSherlock().dispatchPanelClosed(featureId, menu);
|
||||
super.onPanelClosed(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (getSherlock().dispatchKeyEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
getSherlock().dispatchSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
getSherlock().dispatchRestoreInstanceState(savedInstanceState);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Native menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public MenuInflater getSupportMenuInflater() {
|
||||
return getSherlock().getMenuInflater();
|
||||
}
|
||||
|
||||
public void invalidateOptionsMenu() {
|
||||
getSherlock().dispatchInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
public void supportInvalidateOptionsMenu() {
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onCreateOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return getSherlock().dispatchOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openOptionsMenu() {
|
||||
if (!getSherlock().dispatchOpenOptionsMenu()) {
|
||||
super.openOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOptionsMenu() {
|
||||
if (!getSherlock().dispatchCloseOptionsMenu()) {
|
||||
super.closeOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Sherlock menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public boolean onCreatePanelMenu(int featureId, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onCreateOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreparePanel(int featureId, View view, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onPrepareOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onOptionsItemSelected(item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Content
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void addContentView(View view, LayoutParams params) {
|
||||
getSherlock().addContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(int layoutResId) {
|
||||
getSherlock().setContentView(layoutResId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view, LayoutParams params) {
|
||||
getSherlock().setContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view) {
|
||||
getSherlock().setContentView(view);
|
||||
}
|
||||
|
||||
public void requestWindowFeature(long featureId) {
|
||||
getSherlock().requestFeature((int)featureId);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Progress Indication
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setSupportProgress(int progress) {
|
||||
getSherlock().setProgress(progress);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminate(boolean indeterminate) {
|
||||
getSherlock().setProgressBarIndeterminate(indeterminate);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminateVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarIndeterminateVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportSecondaryProgress(int secondaryProgress) {
|
||||
getSherlock().setSecondaryProgress(secondaryProgress);
|
||||
}
|
||||
}
|
@ -1,336 +0,0 @@
|
||||
package com.actionbarsherlock.internal;
|
||||
|
||||
import com.actionbarsherlock.ActionBarSherlock;
|
||||
import com.actionbarsherlock.app.ActionBar;
|
||||
import com.actionbarsherlock.internal.app.ActionBarWrapper;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuWrapper;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
|
||||
@ActionBarSherlock.Implementation(api = 14)
|
||||
public class ActionBarSherlockNative extends ActionBarSherlock {
|
||||
private ActionBarWrapper mActionBar;
|
||||
private ActionModeWrapper mActionMode;
|
||||
private MenuWrapper mMenu;
|
||||
|
||||
public ActionBarSherlockNative(Activity activity, int flags) {
|
||||
super(activity, flags);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ActionBar getActionBar() {
|
||||
if (DEBUG) Log.d(TAG, "[getActionBar]");
|
||||
|
||||
initActionBar();
|
||||
return mActionBar;
|
||||
}
|
||||
|
||||
private void initActionBar() {
|
||||
if (mActionBar != null || mActivity.getActionBar() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mActionBar = new ActionBarWrapper(mActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchInvalidateOptionsMenu() {
|
||||
if (DEBUG) Log.d(TAG, "[dispatchInvalidateOptionsMenu]");
|
||||
|
||||
mActivity.getWindow().invalidatePanelMenu(Window.FEATURE_OPTIONS_PANEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchCreateOptionsMenu(android.view.Menu menu) {
|
||||
if (DEBUG) Log.d(TAG, "[dispatchCreateOptionsMenu] menu: " + menu);
|
||||
|
||||
if (mMenu == null || menu != mMenu.unwrap()) {
|
||||
mMenu = new MenuWrapper(menu);
|
||||
}
|
||||
|
||||
final boolean result = callbackCreateOptionsMenu(mMenu);
|
||||
if (DEBUG) Log.d(TAG, "[dispatchCreateOptionsMenu] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchPrepareOptionsMenu(android.view.Menu menu) {
|
||||
if (DEBUG) Log.d(TAG, "[dispatchPrepareOptionsMenu] menu: " + menu);
|
||||
|
||||
final boolean result = callbackPrepareOptionsMenu(mMenu);
|
||||
if (DEBUG) Log.d(TAG, "[dispatchPrepareOptionsMenu] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchOptionsItemSelected(android.view.MenuItem item) {
|
||||
if (DEBUG) Log.d(TAG, "[dispatchOptionsItemSelected] item: " + item.getTitleCondensed());
|
||||
|
||||
final boolean result = callbackOptionsItemSelected(mMenu.findItem(item));
|
||||
if (DEBUG) Log.d(TAG, "[dispatchOptionsItemSelected] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFeature(int feature) {
|
||||
if (DEBUG) Log.d(TAG, "[hasFeature] feature: " + feature);
|
||||
|
||||
final boolean result = mActivity.getWindow().hasFeature(feature);
|
||||
if (DEBUG) Log.d(TAG, "[hasFeature] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requestFeature(int featureId) {
|
||||
if (DEBUG) Log.d(TAG, "[requestFeature] featureId: " + featureId);
|
||||
|
||||
final boolean result = mActivity.getWindow().requestFeature(featureId);
|
||||
if (DEBUG) Log.d(TAG, "[requestFeature] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUiOptions(int uiOptions) {
|
||||
if (DEBUG) Log.d(TAG, "[setUiOptions] uiOptions: " + uiOptions);
|
||||
|
||||
mActivity.getWindow().setUiOptions(uiOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUiOptions(int uiOptions, int mask) {
|
||||
if (DEBUG) Log.d(TAG, "[setUiOptions] uiOptions: " + uiOptions + ", mask: " + mask);
|
||||
|
||||
mActivity.getWindow().setUiOptions(uiOptions, mask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(int layoutResId) {
|
||||
if (DEBUG) Log.d(TAG, "[setContentView] layoutResId: " + layoutResId);
|
||||
|
||||
mActivity.getWindow().setContentView(layoutResId);
|
||||
initActionBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view, LayoutParams params) {
|
||||
if (DEBUG) Log.d(TAG, "[setContentView] view: " + view + ", params: " + params);
|
||||
|
||||
mActivity.getWindow().setContentView(view, params);
|
||||
initActionBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addContentView(View view, LayoutParams params) {
|
||||
if (DEBUG) Log.d(TAG, "[addContentView] view: " + view + ", params: " + params);
|
||||
|
||||
mActivity.getWindow().addContentView(view, params);
|
||||
initActionBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(CharSequence title) {
|
||||
if (DEBUG) Log.d(TAG, "[setTitle] title: " + title);
|
||||
|
||||
mActivity.getWindow().setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgressBarVisibility(boolean visible) {
|
||||
if (DEBUG) Log.d(TAG, "[setProgressBarVisibility] visible: " + visible);
|
||||
|
||||
mActivity.setProgressBarVisibility(visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgressBarIndeterminateVisibility(boolean visible) {
|
||||
if (DEBUG) Log.d(TAG, "[setProgressBarIndeterminateVisibility] visible: " + visible);
|
||||
|
||||
mActivity.setProgressBarIndeterminateVisibility(visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgressBarIndeterminate(boolean indeterminate) {
|
||||
if (DEBUG) Log.d(TAG, "[setProgressBarIndeterminate] indeterminate: " + indeterminate);
|
||||
|
||||
mActivity.setProgressBarIndeterminate(indeterminate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgress(int progress) {
|
||||
if (DEBUG) Log.d(TAG, "[setProgress] progress: " + progress);
|
||||
|
||||
mActivity.setProgress(progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSecondaryProgress(int secondaryProgress) {
|
||||
if (DEBUG) Log.d(TAG, "[setSecondaryProgress] secondaryProgress: " + secondaryProgress);
|
||||
|
||||
mActivity.setSecondaryProgress(secondaryProgress);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Context getThemedContext() {
|
||||
Context context = mActivity;
|
||||
TypedValue outValue = new TypedValue();
|
||||
mActivity.getTheme().resolveAttribute(android.R.attr.actionBarWidgetTheme, outValue, true);
|
||||
if (outValue.resourceId != 0) {
|
||||
//We are unable to test if this is the same as our current theme
|
||||
//so we just wrap it and hope that if the attribute was specified
|
||||
//then the user is intentionally specifying an alternate theme.
|
||||
context = new ContextThemeWrapper(context, outValue.resourceId);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionMode startActionMode(com.actionbarsherlock.view.ActionMode.Callback callback) {
|
||||
if (DEBUG) Log.d(TAG, "[startActionMode] callback: " + callback);
|
||||
|
||||
if (mActionMode != null) {
|
||||
mActionMode.finish();
|
||||
}
|
||||
ActionModeCallbackWrapper wrapped = null;
|
||||
if (callback != null) {
|
||||
wrapped = new ActionModeCallbackWrapper(callback);
|
||||
}
|
||||
|
||||
//Calling this will trigger the callback wrapper's onCreate which
|
||||
//is where we will set the new instance to mActionMode since we need
|
||||
//to pass it through to the sherlock callbacks and the call below
|
||||
//will not have returned yet to store its value.
|
||||
if (mActivity.startActionMode(wrapped) == null) {
|
||||
mActionMode = null;
|
||||
}
|
||||
if (mActivity instanceof OnActionModeStartedListener && mActionMode != null) {
|
||||
((OnActionModeStartedListener)mActivity).onActionModeStarted(mActionMode);
|
||||
}
|
||||
|
||||
return mActionMode;
|
||||
}
|
||||
|
||||
private class ActionModeCallbackWrapper implements android.view.ActionMode.Callback {
|
||||
private final ActionMode.Callback mCallback;
|
||||
|
||||
public ActionModeCallbackWrapper(ActionMode.Callback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(android.view.ActionMode mode, android.view.Menu menu) {
|
||||
//See ActionBarSherlockNative#startActionMode
|
||||
mActionMode = new ActionModeWrapper(mode);
|
||||
|
||||
return mCallback.onCreateActionMode(mActionMode, mActionMode.getMenu());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(android.view.ActionMode mode, android.view.Menu menu) {
|
||||
return mCallback.onPrepareActionMode(mActionMode, mActionMode.getMenu());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(android.view.ActionMode mode, android.view.MenuItem item) {
|
||||
return mCallback.onActionItemClicked(mActionMode, mActionMode.getMenu().findItem(item));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(android.view.ActionMode mode) {
|
||||
mCallback.onDestroyActionMode(mActionMode);
|
||||
if (mActivity instanceof OnActionModeFinishedListener) {
|
||||
((OnActionModeFinishedListener)mActivity).onActionModeFinished(mActionMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ActionModeWrapper extends ActionMode {
|
||||
private final android.view.ActionMode mActionMode;
|
||||
private MenuWrapper mMenu = null;
|
||||
|
||||
ActionModeWrapper(android.view.ActionMode actionMode) {
|
||||
mActionMode = actionMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(CharSequence title) {
|
||||
mActionMode.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(int resId) {
|
||||
mActionMode.setTitle(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(CharSequence subtitle) {
|
||||
mActionMode.setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(int resId) {
|
||||
mActionMode.setSubtitle(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomView(View view) {
|
||||
mActionMode.setCustomView(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
mActionMode.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
mActionMode.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuWrapper getMenu() {
|
||||
if (mMenu == null) {
|
||||
mMenu = new MenuWrapper(mActionMode.getMenu());
|
||||
}
|
||||
return mMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitle() {
|
||||
return mActionMode.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSubtitle() {
|
||||
return mActionMode.getSubtitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getCustomView() {
|
||||
return mActionMode.getCustomView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuInflater getMenuInflater() {
|
||||
return ActionBarSherlockNative.this.getMenuInflater();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTag(Object tag) {
|
||||
mActionMode.setTag(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTag() {
|
||||
return mActionMode.getTag();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
package com.actionbarsherlock.internal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.DisplayMetrics;
|
||||
import com.actionbarsherlock.R;
|
||||
|
||||
public final class ResourcesCompat {
|
||||
//No instances
|
||||
private ResourcesCompat() {}
|
||||
|
||||
|
||||
/**
|
||||
* Support implementation of {@code getResources().getBoolean()} that we
|
||||
* can use to simulate filtering based on width and smallest width
|
||||
* qualifiers on pre-3.2.
|
||||
*
|
||||
* @param context Context to load booleans from on 3.2+ and to fetch the
|
||||
* display metrics.
|
||||
* @param id Id of boolean to load.
|
||||
* @return Associated boolean value as reflected by the current display
|
||||
* metrics.
|
||||
*/
|
||||
public static boolean getResources_getBoolean(Context context, int id) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
|
||||
return context.getResources().getBoolean(id);
|
||||
}
|
||||
|
||||
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
|
||||
float widthDp = metrics.widthPixels / metrics.density;
|
||||
float heightDp = metrics.heightPixels / metrics.density;
|
||||
float smallestWidthDp = (widthDp < heightDp) ? widthDp : heightDp;
|
||||
|
||||
if (id == R.bool.abs__action_bar_embed_tabs) {
|
||||
if (widthDp >= 480) {
|
||||
return true; //values-w480dp
|
||||
}
|
||||
return false; //values
|
||||
}
|
||||
if (id == R.bool.abs__split_action_bar_is_narrow) {
|
||||
if (widthDp >= 480) {
|
||||
return false; //values-w480dp
|
||||
}
|
||||
return true; //values
|
||||
}
|
||||
if (id == R.bool.abs__action_bar_expanded_action_views_exclusive) {
|
||||
if (smallestWidthDp >= 600) {
|
||||
return false; //values-sw600dp
|
||||
}
|
||||
return true; //values
|
||||
}
|
||||
if (id == R.bool.abs__config_allowActionMenuItemTextWithIcon) {
|
||||
if (widthDp >= 480) {
|
||||
return true; //values-w480dp
|
||||
}
|
||||
return false; //values
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown boolean resource ID " + id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Support implementation of {@code getResources().getInteger()} that we
|
||||
* can use to simulate filtering based on width qualifiers on pre-3.2.
|
||||
*
|
||||
* @param context Context to load integers from on 3.2+ and to fetch the
|
||||
* display metrics.
|
||||
* @param id Id of integer to load.
|
||||
* @return Associated integer value as reflected by the current display
|
||||
* metrics.
|
||||
*/
|
||||
public static int getResources_getInteger(Context context, int id) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
|
||||
return context.getResources().getInteger(id);
|
||||
}
|
||||
|
||||
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
|
||||
float widthDp = metrics.widthPixels / metrics.density;
|
||||
|
||||
if (id == R.integer.abs__max_action_buttons) {
|
||||
if (widthDp >= 600) {
|
||||
return 5; //values-w600dp
|
||||
}
|
||||
if (widthDp >= 500) {
|
||||
return 4; //values-w500dp
|
||||
}
|
||||
if (widthDp >= 360) {
|
||||
return 3; //values-w360dp
|
||||
}
|
||||
return 2; //values
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown integer resource ID " + id);
|
||||
}
|
||||
}
|
@ -1,468 +0,0 @@
|
||||
package com.actionbarsherlock.internal.app;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.view.View;
|
||||
import android.widget.SpinnerAdapter;
|
||||
|
||||
import com.actionbarsherlock.app.ActionBar;
|
||||
|
||||
public class ActionBarWrapper extends ActionBar implements android.app.ActionBar.OnNavigationListener, android.app.ActionBar.OnMenuVisibilityListener {
|
||||
private final Activity mActivity;
|
||||
private final android.app.ActionBar mActionBar;
|
||||
private ActionBar.OnNavigationListener mNavigationListener;
|
||||
private Set<OnMenuVisibilityListener> mMenuVisibilityListeners = new HashSet<OnMenuVisibilityListener>(1);
|
||||
private FragmentTransaction mFragmentTransaction;
|
||||
|
||||
|
||||
public ActionBarWrapper(Activity activity) {
|
||||
mActivity = activity;
|
||||
mActionBar = activity.getActionBar();
|
||||
if (mActionBar != null) {
|
||||
mActionBar.addOnMenuVisibilityListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setHomeButtonEnabled(boolean enabled) {
|
||||
mActionBar.setHomeButtonEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getThemedContext() {
|
||||
return mActionBar.getThemedContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomView(View view) {
|
||||
mActionBar.setCustomView(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomView(View view, LayoutParams layoutParams) {
|
||||
android.app.ActionBar.LayoutParams lp = new android.app.ActionBar.LayoutParams(layoutParams);
|
||||
lp.gravity = layoutParams.gravity;
|
||||
lp.bottomMargin = layoutParams.bottomMargin;
|
||||
lp.topMargin = layoutParams.topMargin;
|
||||
lp.leftMargin = layoutParams.leftMargin;
|
||||
lp.rightMargin = layoutParams.rightMargin;
|
||||
mActionBar.setCustomView(view, lp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomView(int resId) {
|
||||
mActionBar.setCustomView(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIcon(int resId) {
|
||||
mActionBar.setIcon(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIcon(Drawable icon) {
|
||||
mActionBar.setIcon(icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogo(int resId) {
|
||||
mActionBar.setLogo(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogo(Drawable logo) {
|
||||
mActionBar.setLogo(logo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
|
||||
mNavigationListener = callback;
|
||||
mActionBar.setListNavigationCallbacks(adapter, (callback != null) ? this : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
|
||||
//This should never be a NullPointerException since we only set
|
||||
//ourselves as the listener when the callback is not null.
|
||||
return mNavigationListener.onNavigationItemSelected(itemPosition, itemId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedNavigationItem(int position) {
|
||||
mActionBar.setSelectedNavigationItem(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSelectedNavigationIndex() {
|
||||
return mActionBar.getSelectedNavigationIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNavigationItemCount() {
|
||||
return mActionBar.getNavigationItemCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(CharSequence title) {
|
||||
mActionBar.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(int resId) {
|
||||
mActionBar.setTitle(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(CharSequence subtitle) {
|
||||
mActionBar.setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(int resId) {
|
||||
mActionBar.setSubtitle(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayOptions(int options) {
|
||||
mActionBar.setDisplayOptions(options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayOptions(int options, int mask) {
|
||||
mActionBar.setDisplayOptions(options, mask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayUseLogoEnabled(boolean useLogo) {
|
||||
mActionBar.setDisplayUseLogoEnabled(useLogo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayShowHomeEnabled(boolean showHome) {
|
||||
mActionBar.setDisplayShowHomeEnabled(showHome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
|
||||
mActionBar.setDisplayHomeAsUpEnabled(showHomeAsUp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayShowTitleEnabled(boolean showTitle) {
|
||||
mActionBar.setDisplayShowTitleEnabled(showTitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayShowCustomEnabled(boolean showCustom) {
|
||||
mActionBar.setDisplayShowCustomEnabled(showCustom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackgroundDrawable(Drawable d) {
|
||||
mActionBar.setBackgroundDrawable(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStackedBackgroundDrawable(Drawable d) {
|
||||
mActionBar.setStackedBackgroundDrawable(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSplitBackgroundDrawable(Drawable d) {
|
||||
mActionBar.setSplitBackgroundDrawable(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getCustomView() {
|
||||
return mActionBar.getCustomView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitle() {
|
||||
return mActionBar.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSubtitle() {
|
||||
return mActionBar.getSubtitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNavigationMode() {
|
||||
return mActionBar.getNavigationMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNavigationMode(int mode) {
|
||||
mActionBar.setNavigationMode(mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDisplayOptions() {
|
||||
return mActionBar.getDisplayOptions();
|
||||
}
|
||||
|
||||
public class TabWrapper extends ActionBar.Tab implements android.app.ActionBar.TabListener {
|
||||
final android.app.ActionBar.Tab mNativeTab;
|
||||
private Object mTag;
|
||||
private TabListener mListener;
|
||||
|
||||
public TabWrapper(android.app.ActionBar.Tab nativeTab) {
|
||||
mNativeTab = nativeTab;
|
||||
mNativeTab.setTag(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPosition() {
|
||||
return mNativeTab.getPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getIcon() {
|
||||
return mNativeTab.getIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getText() {
|
||||
return mNativeTab.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setIcon(Drawable icon) {
|
||||
mNativeTab.setIcon(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setIcon(int resId) {
|
||||
mNativeTab.setIcon(resId);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setText(CharSequence text) {
|
||||
mNativeTab.setText(text);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setText(int resId) {
|
||||
mNativeTab.setText(resId);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setCustomView(View view) {
|
||||
mNativeTab.setCustomView(view);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setCustomView(int layoutResId) {
|
||||
mNativeTab.setCustomView(layoutResId);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getCustomView() {
|
||||
return mNativeTab.getCustomView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setTag(Object obj) {
|
||||
mTag = obj;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTag() {
|
||||
return mTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setTabListener(TabListener listener) {
|
||||
mNativeTab.setTabListener(listener != null ? this : null);
|
||||
mListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void select() {
|
||||
mNativeTab.select();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setContentDescription(int resId) {
|
||||
mNativeTab.setContentDescription(resId);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setContentDescription(CharSequence contentDesc) {
|
||||
mNativeTab.setContentDescription(contentDesc);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getContentDescription() {
|
||||
return mNativeTab.getContentDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) {
|
||||
if (mListener != null) {
|
||||
FragmentTransaction trans = null;
|
||||
if (mActivity instanceof FragmentActivity) {
|
||||
trans = ((FragmentActivity)mActivity).getSupportFragmentManager().beginTransaction()
|
||||
.disallowAddToBackStack();
|
||||
}
|
||||
|
||||
mListener.onTabReselected(this, trans);
|
||||
|
||||
if (trans != null && !trans.isEmpty()) {
|
||||
trans.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabSelected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) {
|
||||
if (mListener != null) {
|
||||
|
||||
if (mFragmentTransaction == null && mActivity instanceof FragmentActivity) {
|
||||
mFragmentTransaction = ((FragmentActivity)mActivity).getSupportFragmentManager().beginTransaction()
|
||||
.disallowAddToBackStack();
|
||||
}
|
||||
|
||||
mListener.onTabSelected(this, mFragmentTransaction);
|
||||
|
||||
if (mFragmentTransaction != null) {
|
||||
if (!mFragmentTransaction.isEmpty()) {
|
||||
mFragmentTransaction.commit();
|
||||
}
|
||||
mFragmentTransaction = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) {
|
||||
if (mListener != null) {
|
||||
FragmentTransaction trans = null;
|
||||
if (mActivity instanceof FragmentActivity) {
|
||||
trans = ((FragmentActivity)mActivity).getSupportFragmentManager().beginTransaction()
|
||||
.disallowAddToBackStack();
|
||||
mFragmentTransaction = trans;
|
||||
}
|
||||
|
||||
mListener.onTabUnselected(this, trans);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab newTab() {
|
||||
return new TabWrapper(mActionBar.newTab());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTab(Tab tab) {
|
||||
mActionBar.addTab(((TabWrapper)tab).mNativeTab);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTab(Tab tab, boolean setSelected) {
|
||||
mActionBar.addTab(((TabWrapper)tab).mNativeTab, setSelected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTab(Tab tab, int position) {
|
||||
mActionBar.addTab(((TabWrapper)tab).mNativeTab, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTab(Tab tab, int position, boolean setSelected) {
|
||||
mActionBar.addTab(((TabWrapper)tab).mNativeTab, position, setSelected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTab(Tab tab) {
|
||||
mActionBar.removeTab(((TabWrapper)tab).mNativeTab);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTabAt(int position) {
|
||||
mActionBar.removeTabAt(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllTabs() {
|
||||
mActionBar.removeAllTabs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectTab(Tab tab) {
|
||||
mActionBar.selectTab(((TabWrapper)tab).mNativeTab);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getSelectedTab() {
|
||||
android.app.ActionBar.Tab selected = mActionBar.getSelectedTab();
|
||||
return (selected != null) ? (Tab)selected.getTag() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTabAt(int index) {
|
||||
android.app.ActionBar.Tab selected = mActionBar.getTabAt(index);
|
||||
return (selected != null) ? (Tab)selected.getTag() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTabCount() {
|
||||
return mActionBar.getTabCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return mActionBar.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
mActionBar.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
mActionBar.hide();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowing() {
|
||||
return mActionBar.isShowing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
|
||||
mMenuVisibilityListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
|
||||
mMenuVisibilityListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMenuVisibilityChanged(boolean isVisible) {
|
||||
for (OnMenuVisibilityListener listener : mMenuVisibilityListeners) {
|
||||
listener.onMenuVisibilityChanged(isVisible);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,278 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
/**
|
||||
* This is the superclass for classes which provide basic support for animations which can be
|
||||
* started, ended, and have <code>AnimatorListeners</code> added to them.
|
||||
*/
|
||||
public abstract class Animator implements Cloneable {
|
||||
|
||||
|
||||
/**
|
||||
* The set of listeners to be sent events through the life of an animation.
|
||||
*/
|
||||
ArrayList<AnimatorListener> mListeners = null;
|
||||
|
||||
/**
|
||||
* Starts this animation. If the animation has a nonzero startDelay, the animation will start
|
||||
* running after that delay elapses. A non-delayed animation will have its initial
|
||||
* value(s) set immediately, followed by calls to
|
||||
* {@link AnimatorListener#onAnimationStart(Animator)} for any listeners of this animator.
|
||||
*
|
||||
* <p>The animation started by calling this method will be run on the thread that called
|
||||
* this method. This thread should have a Looper on it (a runtime exception will be thrown if
|
||||
* this is not the case). Also, if the animation will animate
|
||||
* properties of objects in the view hierarchy, then the calling thread should be the UI
|
||||
* thread for that view hierarchy.</p>
|
||||
*
|
||||
*/
|
||||
public void start() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the animation. Unlike {@link #end()}, <code>cancel()</code> causes the animation to
|
||||
* stop in its tracks, sending an
|
||||
* {@link android.animation.Animator.AnimatorListener#onAnimationCancel(Animator)} to
|
||||
* its listeners, followed by an
|
||||
* {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} message.
|
||||
*
|
||||
* <p>This method must be called on the thread that is running the animation.</p>
|
||||
*/
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the animation. This causes the animation to assign the end value of the property being
|
||||
* animated, then calling the
|
||||
* {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} method on
|
||||
* its listeners.
|
||||
*
|
||||
* <p>This method must be called on the thread that is running the animation.</p>
|
||||
*/
|
||||
public void end() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount of time, in milliseconds, to delay starting the animation after
|
||||
* {@link #start()} is called.
|
||||
*
|
||||
* @return the number of milliseconds to delay running the animation
|
||||
*/
|
||||
public abstract long getStartDelay();
|
||||
|
||||
/**
|
||||
* The amount of time, in milliseconds, to delay starting the animation after
|
||||
* {@link #start()} is called.
|
||||
|
||||
* @param startDelay The amount of the delay, in milliseconds
|
||||
*/
|
||||
public abstract void setStartDelay(long startDelay);
|
||||
|
||||
|
||||
/**
|
||||
* Sets the length of the animation.
|
||||
*
|
||||
* @param duration The length of the animation, in milliseconds.
|
||||
*/
|
||||
public abstract Animator setDuration(long duration);
|
||||
|
||||
/**
|
||||
* Gets the length of the animation.
|
||||
*
|
||||
* @return The length of the animation, in milliseconds.
|
||||
*/
|
||||
public abstract long getDuration();
|
||||
|
||||
/**
|
||||
* The time interpolator used in calculating the elapsed fraction of this animation. The
|
||||
* interpolator determines whether the animation runs with linear or non-linear motion,
|
||||
* such as acceleration and deceleration. The default value is
|
||||
* {@link android.view.animation.AccelerateDecelerateInterpolator}
|
||||
*
|
||||
* @param value the interpolator to be used by this animation
|
||||
*/
|
||||
public abstract void setInterpolator(/*Time*/Interpolator value);
|
||||
|
||||
/**
|
||||
* Returns whether this Animator is currently running (having been started and gone past any
|
||||
* initial startDelay period and not yet ended).
|
||||
*
|
||||
* @return Whether the Animator is running.
|
||||
*/
|
||||
public abstract boolean isRunning();
|
||||
|
||||
/**
|
||||
* Returns whether this Animator has been started and not yet ended. This state is a superset
|
||||
* of the state of {@link #isRunning()}, because an Animator with a nonzero
|
||||
* {@link #getStartDelay() startDelay} will return true for {@link #isStarted()} during the
|
||||
* delay phase, whereas {@link #isRunning()} will return true only after the delay phase
|
||||
* is complete.
|
||||
*
|
||||
* @return Whether the Animator has been started and not yet ended.
|
||||
*/
|
||||
public boolean isStarted() {
|
||||
// Default method returns value for isRunning(). Subclasses should override to return a
|
||||
// real value.
|
||||
return isRunning();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to the set of listeners that are sent events through the life of an
|
||||
* animation, such as start, repeat, and end.
|
||||
*
|
||||
* @param listener the listener to be added to the current set of listeners for this animation.
|
||||
*/
|
||||
public void addListener(AnimatorListener listener) {
|
||||
if (mListeners == null) {
|
||||
mListeners = new ArrayList<AnimatorListener>();
|
||||
}
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener from the set listening to this animation.
|
||||
*
|
||||
* @param listener the listener to be removed from the current set of listeners for this
|
||||
* animation.
|
||||
*/
|
||||
public void removeListener(AnimatorListener listener) {
|
||||
if (mListeners == null) {
|
||||
return;
|
||||
}
|
||||
mListeners.remove(listener);
|
||||
if (mListeners.size() == 0) {
|
||||
mListeners = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of {@link android.animation.Animator.AnimatorListener} objects that are currently
|
||||
* listening for events on this <code>Animator</code> object.
|
||||
*
|
||||
* @return ArrayList<AnimatorListener> The set of listeners.
|
||||
*/
|
||||
public ArrayList<AnimatorListener> getListeners() {
|
||||
return mListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all listeners from this object. This is equivalent to calling
|
||||
* <code>getListeners()</code> followed by calling <code>clear()</code> on the
|
||||
* returned list of listeners.
|
||||
*/
|
||||
public void removeAllListeners() {
|
||||
if (mListeners != null) {
|
||||
mListeners.clear();
|
||||
mListeners = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Animator clone() {
|
||||
try {
|
||||
final Animator anim = (Animator) super.clone();
|
||||
if (mListeners != null) {
|
||||
ArrayList<AnimatorListener> oldListeners = mListeners;
|
||||
anim.mListeners = new ArrayList<AnimatorListener>();
|
||||
int numListeners = oldListeners.size();
|
||||
for (int i = 0; i < numListeners; ++i) {
|
||||
anim.mListeners.add(oldListeners.get(i));
|
||||
}
|
||||
}
|
||||
return anim;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tells the object to use appropriate information to extract
|
||||
* starting values for the animation. For example, a AnimatorSet object will pass
|
||||
* this call to its child objects to tell them to set up the values. A
|
||||
* ObjectAnimator object will use the information it has about its target object
|
||||
* and PropertyValuesHolder objects to get the start values for its properties.
|
||||
* An ValueAnimator object will ignore the request since it does not have enough
|
||||
* information (such as a target object) to gather these values.
|
||||
*/
|
||||
public void setupStartValues() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tells the object to use appropriate information to extract
|
||||
* ending values for the animation. For example, a AnimatorSet object will pass
|
||||
* this call to its child objects to tell them to set up the values. A
|
||||
* ObjectAnimator object will use the information it has about its target object
|
||||
* and PropertyValuesHolder objects to get the start values for its properties.
|
||||
* An ValueAnimator object will ignore the request since it does not have enough
|
||||
* information (such as a target object) to gather these values.
|
||||
*/
|
||||
public void setupEndValues() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target object whose property will be animated by this animation. Not all subclasses
|
||||
* operate on target objects (for example, {@link ValueAnimator}, but this method
|
||||
* is on the superclass for the convenience of dealing generically with those subclasses
|
||||
* that do handle targets.
|
||||
*
|
||||
* @param target The object being animated
|
||||
*/
|
||||
public void setTarget(Object target) {
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>An animation listener receives notifications from an animation.
|
||||
* Notifications indicate animation related events, such as the end or the
|
||||
* repetition of the animation.</p>
|
||||
*/
|
||||
public static interface AnimatorListener {
|
||||
/**
|
||||
* <p>Notifies the start of the animation.</p>
|
||||
*
|
||||
* @param animation The started animation.
|
||||
*/
|
||||
void onAnimationStart(Animator animation);
|
||||
|
||||
/**
|
||||
* <p>Notifies the end of the animation. This callback is not invoked
|
||||
* for animations with repeat count set to INFINITE.</p>
|
||||
*
|
||||
* @param animation The animation which reached its end.
|
||||
*/
|
||||
void onAnimationEnd(Animator animation);
|
||||
|
||||
/**
|
||||
* <p>Notifies the cancellation of the animation. This callback is not invoked
|
||||
* for animations with repeat count set to INFINITE.</p>
|
||||
*
|
||||
* @param animation The animation which was canceled.
|
||||
*/
|
||||
void onAnimationCancel(Animator animation);
|
||||
|
||||
/**
|
||||
* <p>Notifies the repetition of the animation.</p>
|
||||
*
|
||||
* @param animation The animation which was repeated.
|
||||
*/
|
||||
void onAnimationRepeat(Animator animation);
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This adapter class provides empty implementations of the methods from {@link android.animation.Animator.AnimatorListener}.
|
||||
* Any custom listener that cares only about a subset of the methods of this listener can
|
||||
* simply subclass this adapter class instead of implementing the interface directly.
|
||||
*/
|
||||
public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
}
|
||||
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This evaluator can be used to perform type interpolation between <code>float</code> values.
|
||||
*/
|
||||
public class FloatEvaluator implements TypeEvaluator<Number> {
|
||||
|
||||
/**
|
||||
* This function returns the result of linearly interpolating the start and end values, with
|
||||
* <code>fraction</code> representing the proportion between the start and end values. The
|
||||
* calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
|
||||
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
|
||||
* and <code>t</code> is <code>fraction</code>.
|
||||
*
|
||||
* @param fraction The fraction from the starting to the ending values
|
||||
* @param startValue The start value; should be of type <code>float</code> or
|
||||
* <code>Float</code>
|
||||
* @param endValue The end value; should be of type <code>float</code> or <code>Float</code>
|
||||
* @return A linear interpolation between the start and end values, given the
|
||||
* <code>fraction</code> parameter.
|
||||
*/
|
||||
public Float evaluate(float fraction, Number startValue, Number endValue) {
|
||||
float startFloat = startValue.floatValue();
|
||||
return startFloat + fraction * (endValue.floatValue() - startFloat);
|
||||
}
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.FloatKeyframe;
|
||||
|
||||
/**
|
||||
* This class holds a collection of FloatKeyframe objects and is called by ValueAnimator to calculate
|
||||
* values between those keyframes for a given animation. The class internal to the animation
|
||||
* package because it is an implementation detail of how Keyframes are stored and used.
|
||||
*
|
||||
* <p>This type-specific subclass of KeyframeSet, along with the other type-specific subclass for
|
||||
* int, exists to speed up the getValue() method when there is no custom
|
||||
* TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the
|
||||
* Object equivalents of these primitive types.</p>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
class FloatKeyframeSet extends KeyframeSet {
|
||||
private float firstValue;
|
||||
private float lastValue;
|
||||
private float deltaValue;
|
||||
private boolean firstTime = true;
|
||||
|
||||
public FloatKeyframeSet(FloatKeyframe... keyframes) {
|
||||
super(keyframes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(float fraction) {
|
||||
return getFloatValue(fraction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatKeyframeSet clone() {
|
||||
ArrayList<Keyframe> keyframes = mKeyframes;
|
||||
int numKeyframes = mKeyframes.size();
|
||||
FloatKeyframe[] newKeyframes = new FloatKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
newKeyframes[i] = (FloatKeyframe) keyframes.get(i).clone();
|
||||
}
|
||||
FloatKeyframeSet newSet = new FloatKeyframeSet(newKeyframes);
|
||||
return newSet;
|
||||
}
|
||||
|
||||
public float getFloatValue(float fraction) {
|
||||
if (mNumKeyframes == 2) {
|
||||
if (firstTime) {
|
||||
firstTime = false;
|
||||
firstValue = ((FloatKeyframe) mKeyframes.get(0)).getFloatValue();
|
||||
lastValue = ((FloatKeyframe) mKeyframes.get(1)).getFloatValue();
|
||||
deltaValue = lastValue - firstValue;
|
||||
}
|
||||
if (mInterpolator != null) {
|
||||
fraction = mInterpolator.getInterpolation(fraction);
|
||||
}
|
||||
if (mEvaluator == null) {
|
||||
return firstValue + fraction * deltaValue;
|
||||
} else {
|
||||
return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).floatValue();
|
||||
}
|
||||
}
|
||||
if (fraction <= 0f) {
|
||||
final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
|
||||
final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(1);
|
||||
float prevValue = prevKeyframe.getFloatValue();
|
||||
float nextValue = nextKeyframe.getFloatValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + intervalFraction * (nextValue - prevValue) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
floatValue();
|
||||
} else if (fraction >= 1f) {
|
||||
final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 2);
|
||||
final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 1);
|
||||
float prevValue = prevKeyframe.getFloatValue();
|
||||
float nextValue = nextKeyframe.getFloatValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + intervalFraction * (nextValue - prevValue) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
floatValue();
|
||||
}
|
||||
FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
|
||||
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||
FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(i);
|
||||
if (fraction < nextKeyframe.getFraction()) {
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
|
||||
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
|
||||
float prevValue = prevKeyframe.getFloatValue();
|
||||
float nextValue = nextKeyframe.getFloatValue();
|
||||
return mEvaluator == null ?
|
||||
prevValue + intervalFraction * (nextValue - prevValue) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
floatValue();
|
||||
}
|
||||
prevKeyframe = nextKeyframe;
|
||||
}
|
||||
// shouldn't get here
|
||||
return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This evaluator can be used to perform type interpolation between <code>int</code> values.
|
||||
*/
|
||||
public class IntEvaluator implements TypeEvaluator<Integer> {
|
||||
|
||||
/**
|
||||
* This function returns the result of linearly interpolating the start and end values, with
|
||||
* <code>fraction</code> representing the proportion between the start and end values. The
|
||||
* calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
|
||||
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
|
||||
* and <code>t</code> is <code>fraction</code>.
|
||||
*
|
||||
* @param fraction The fraction from the starting to the ending values
|
||||
* @param startValue The start value; should be of type <code>int</code> or
|
||||
* <code>Integer</code>
|
||||
* @param endValue The end value; should be of type <code>int</code> or <code>Integer</code>
|
||||
* @return A linear interpolation between the start and end values, given the
|
||||
* <code>fraction</code> parameter.
|
||||
*/
|
||||
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
|
||||
int startInt = startValue;
|
||||
return (int)(startInt + fraction * (endValue - startInt));
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.IntKeyframe;
|
||||
|
||||
/**
|
||||
* This class holds a collection of IntKeyframe objects and is called by ValueAnimator to calculate
|
||||
* values between those keyframes for a given animation. The class internal to the animation
|
||||
* package because it is an implementation detail of how Keyframes are stored and used.
|
||||
*
|
||||
* <p>This type-specific subclass of KeyframeSet, along with the other type-specific subclass for
|
||||
* float, exists to speed up the getValue() method when there is no custom
|
||||
* TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the
|
||||
* Object equivalents of these primitive types.</p>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
class IntKeyframeSet extends KeyframeSet {
|
||||
private int firstValue;
|
||||
private int lastValue;
|
||||
private int deltaValue;
|
||||
private boolean firstTime = true;
|
||||
|
||||
public IntKeyframeSet(IntKeyframe... keyframes) {
|
||||
super(keyframes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(float fraction) {
|
||||
return getIntValue(fraction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntKeyframeSet clone() {
|
||||
ArrayList<Keyframe> keyframes = mKeyframes;
|
||||
int numKeyframes = mKeyframes.size();
|
||||
IntKeyframe[] newKeyframes = new IntKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
newKeyframes[i] = (IntKeyframe) keyframes.get(i).clone();
|
||||
}
|
||||
IntKeyframeSet newSet = new IntKeyframeSet(newKeyframes);
|
||||
return newSet;
|
||||
}
|
||||
|
||||
public int getIntValue(float fraction) {
|
||||
if (mNumKeyframes == 2) {
|
||||
if (firstTime) {
|
||||
firstTime = false;
|
||||
firstValue = ((IntKeyframe) mKeyframes.get(0)).getIntValue();
|
||||
lastValue = ((IntKeyframe) mKeyframes.get(1)).getIntValue();
|
||||
deltaValue = lastValue - firstValue;
|
||||
}
|
||||
if (mInterpolator != null) {
|
||||
fraction = mInterpolator.getInterpolation(fraction);
|
||||
}
|
||||
if (mEvaluator == null) {
|
||||
return firstValue + (int)(fraction * deltaValue);
|
||||
} else {
|
||||
return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).intValue();
|
||||
}
|
||||
}
|
||||
if (fraction <= 0f) {
|
||||
final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0);
|
||||
final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(1);
|
||||
int prevValue = prevKeyframe.getIntValue();
|
||||
int nextValue = nextKeyframe.getIntValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + (int)(intervalFraction * (nextValue - prevValue)) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
intValue();
|
||||
} else if (fraction >= 1f) {
|
||||
final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 2);
|
||||
final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 1);
|
||||
int prevValue = prevKeyframe.getIntValue();
|
||||
int nextValue = nextKeyframe.getIntValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + (int)(intervalFraction * (nextValue - prevValue)) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).intValue();
|
||||
}
|
||||
IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0);
|
||||
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||
IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(i);
|
||||
if (fraction < nextKeyframe.getFraction()) {
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
|
||||
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
|
||||
int prevValue = prevKeyframe.getIntValue();
|
||||
int nextValue = nextKeyframe.getIntValue();
|
||||
return mEvaluator == null ?
|
||||
prevValue + (int)(intervalFraction * (nextValue - prevValue)) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
intValue();
|
||||
}
|
||||
prevKeyframe = nextKeyframe;
|
||||
}
|
||||
// shouldn't get here
|
||||
return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).intValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,361 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
/**
|
||||
* This class holds a time/value pair for an animation. The Keyframe class is used
|
||||
* by {@link ValueAnimator} to define the values that the animation target will have over the course
|
||||
* of the animation. As the time proceeds from one keyframe to the other, the value of the
|
||||
* target object will animate between the value at the previous keyframe and the value at the
|
||||
* next keyframe. Each keyframe also holds an optional {@link TimeInterpolator}
|
||||
* object, which defines the time interpolation over the intervalue preceding the keyframe.
|
||||
*
|
||||
* <p>The Keyframe class itself is abstract. The type-specific factory methods will return
|
||||
* a subclass of Keyframe specific to the type of value being stored. This is done to improve
|
||||
* performance when dealing with the most common cases (e.g., <code>float</code> and
|
||||
* <code>int</code> values). Other types will fall into a more general Keyframe class that
|
||||
* treats its values as Objects. Unless your animation requires dealing with a custom type
|
||||
* or a data structure that needs to be animated directly (and evaluated using an implementation
|
||||
* of {@link TypeEvaluator}), you should stick to using float and int as animations using those
|
||||
* types have lower runtime overhead than other types.</p>
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public abstract class Keyframe implements Cloneable {
|
||||
/**
|
||||
* The time at which mValue will hold true.
|
||||
*/
|
||||
float mFraction;
|
||||
|
||||
/**
|
||||
* The type of the value in this Keyframe. This type is determined at construction time,
|
||||
* based on the type of the <code>value</code> object passed into the constructor.
|
||||
*/
|
||||
Class mValueType;
|
||||
|
||||
/**
|
||||
* The optional time interpolator for the interval preceding this keyframe. A null interpolator
|
||||
* (the default) results in linear interpolation over the interval.
|
||||
*/
|
||||
private /*Time*/Interpolator mInterpolator = null;
|
||||
|
||||
/**
|
||||
* Flag to indicate whether this keyframe has a valid value. This flag is used when an
|
||||
* animation first starts, to populate placeholder keyframes with real values derived
|
||||
* from the target object.
|
||||
*/
|
||||
boolean mHasValue = false;
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public static Keyframe ofInt(float fraction, int value) {
|
||||
return new IntKeyframe(fraction, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time. The value at this time will be derived
|
||||
* from the target object when the animation first starts (note that this implies that keyframes
|
||||
* with no initial value must be used as part of an {@link ObjectAnimator}).
|
||||
* The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
*/
|
||||
public static Keyframe ofInt(float fraction) {
|
||||
return new IntKeyframe(fraction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public static Keyframe ofFloat(float fraction, float value) {
|
||||
return new FloatKeyframe(fraction, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time. The value at this time will be derived
|
||||
* from the target object when the animation first starts (note that this implies that keyframes
|
||||
* with no initial value must be used as part of an {@link ObjectAnimator}).
|
||||
* The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
*/
|
||||
public static Keyframe ofFloat(float fraction) {
|
||||
return new FloatKeyframe(fraction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public static Keyframe ofObject(float fraction, Object value) {
|
||||
return new ObjectKeyframe(fraction, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time. The value at this time will be derived
|
||||
* from the target object when the animation first starts (note that this implies that keyframes
|
||||
* with no initial value must be used as part of an {@link ObjectAnimator}).
|
||||
* The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
*/
|
||||
public static Keyframe ofObject(float fraction) {
|
||||
return new ObjectKeyframe(fraction, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this keyframe has a valid value. This method is called internally when
|
||||
* an {@link ObjectAnimator} first starts; keyframes without values are assigned values at
|
||||
* that time by deriving the value for the property from the target object.
|
||||
*
|
||||
* @return boolean Whether this object has a value assigned.
|
||||
*/
|
||||
public boolean hasValue() {
|
||||
return mHasValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value for this Keyframe.
|
||||
*
|
||||
* @return The value for this Keyframe.
|
||||
*/
|
||||
public abstract Object getValue();
|
||||
|
||||
/**
|
||||
* Sets the value for this Keyframe.
|
||||
*
|
||||
* @param value value for this Keyframe.
|
||||
*/
|
||||
public abstract void setValue(Object value);
|
||||
|
||||
/**
|
||||
* Gets the time for this keyframe, as a fraction of the overall animation duration.
|
||||
*
|
||||
* @return The time associated with this keyframe, as a fraction of the overall animation
|
||||
* duration. This should be a value between 0 and 1.
|
||||
*/
|
||||
public float getFraction() {
|
||||
return mFraction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time for this keyframe, as a fraction of the overall animation duration.
|
||||
*
|
||||
* @param fraction time associated with this keyframe, as a fraction of the overall animation
|
||||
* duration. This should be a value between 0 and 1.
|
||||
*/
|
||||
public void setFraction(float fraction) {
|
||||
mFraction = fraction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the optional interpolator for this Keyframe. A value of <code>null</code> indicates
|
||||
* that there is no interpolation, which is the same as linear interpolation.
|
||||
*
|
||||
* @return The optional interpolator for this Keyframe.
|
||||
*/
|
||||
public /*Time*/Interpolator getInterpolator() {
|
||||
return mInterpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the optional interpolator for this Keyframe. A value of <code>null</code> indicates
|
||||
* that there is no interpolation, which is the same as linear interpolation.
|
||||
*
|
||||
* @return The optional interpolator for this Keyframe.
|
||||
*/
|
||||
public void setInterpolator(/*Time*/Interpolator interpolator) {
|
||||
mInterpolator = interpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of keyframe. This information is used by ValueAnimator to determine the type of
|
||||
* {@link TypeEvaluator} to use when calculating values between keyframes. The type is based
|
||||
* on the type of Keyframe created.
|
||||
*
|
||||
* @return The type of the value stored in the Keyframe.
|
||||
*/
|
||||
public Class getType() {
|
||||
return mValueType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Keyframe clone();
|
||||
|
||||
/**
|
||||
* This internal subclass is used for all types which are not int or float.
|
||||
*/
|
||||
static class ObjectKeyframe extends Keyframe {
|
||||
|
||||
/**
|
||||
* The value of the animation at the time mFraction.
|
||||
*/
|
||||
Object mValue;
|
||||
|
||||
ObjectKeyframe(float fraction, Object value) {
|
||||
mFraction = fraction;
|
||||
mValue = value;
|
||||
mHasValue = (value != null);
|
||||
mValueType = mHasValue ? value.getClass() : Object.class;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
mValue = value;
|
||||
mHasValue = (value != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectKeyframe clone() {
|
||||
ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), mValue);
|
||||
kfClone.setInterpolator(getInterpolator());
|
||||
return kfClone;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal subclass used when the keyframe value is of type int.
|
||||
*/
|
||||
static class IntKeyframe extends Keyframe {
|
||||
|
||||
/**
|
||||
* The value of the animation at the time mFraction.
|
||||
*/
|
||||
int mValue;
|
||||
|
||||
IntKeyframe(float fraction, int value) {
|
||||
mFraction = fraction;
|
||||
mValue = value;
|
||||
mValueType = int.class;
|
||||
mHasValue = true;
|
||||
}
|
||||
|
||||
IntKeyframe(float fraction) {
|
||||
mFraction = fraction;
|
||||
mValueType = int.class;
|
||||
}
|
||||
|
||||
public int getIntValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
if (value != null && value.getClass() == Integer.class) {
|
||||
mValue = ((Integer)value).intValue();
|
||||
mHasValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntKeyframe clone() {
|
||||
IntKeyframe kfClone = new IntKeyframe(getFraction(), mValue);
|
||||
kfClone.setInterpolator(getInterpolator());
|
||||
return kfClone;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal subclass used when the keyframe value is of type float.
|
||||
*/
|
||||
static class FloatKeyframe extends Keyframe {
|
||||
/**
|
||||
* The value of the animation at the time mFraction.
|
||||
*/
|
||||
float mValue;
|
||||
|
||||
FloatKeyframe(float fraction, float value) {
|
||||
mFraction = fraction;
|
||||
mValue = value;
|
||||
mValueType = float.class;
|
||||
mHasValue = true;
|
||||
}
|
||||
|
||||
FloatKeyframe(float fraction) {
|
||||
mFraction = fraction;
|
||||
mValueType = float.class;
|
||||
}
|
||||
|
||||
public float getFloatValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
if (value != null && value.getClass() == Float.class) {
|
||||
mValue = ((Float)value).floatValue();
|
||||
mHasValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatKeyframe clone() {
|
||||
FloatKeyframe kfClone = new FloatKeyframe(getFraction(), mValue);
|
||||
kfClone.setInterpolator(getInterpolator());
|
||||
return kfClone;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,227 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.FloatKeyframe;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.IntKeyframe;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.ObjectKeyframe;
|
||||
|
||||
/**
|
||||
* This class holds a collection of Keyframe objects and is called by ValueAnimator to calculate
|
||||
* values between those keyframes for a given animation. The class internal to the animation
|
||||
* package because it is an implementation detail of how Keyframes are stored and used.
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class KeyframeSet {
|
||||
|
||||
int mNumKeyframes;
|
||||
|
||||
Keyframe mFirstKeyframe;
|
||||
Keyframe mLastKeyframe;
|
||||
/*Time*/Interpolator mInterpolator; // only used in the 2-keyframe case
|
||||
ArrayList<Keyframe> mKeyframes; // only used when there are not 2 keyframes
|
||||
TypeEvaluator mEvaluator;
|
||||
|
||||
|
||||
public KeyframeSet(Keyframe... keyframes) {
|
||||
mNumKeyframes = keyframes.length;
|
||||
mKeyframes = new ArrayList<Keyframe>();
|
||||
mKeyframes.addAll(Arrays.asList(keyframes));
|
||||
mFirstKeyframe = mKeyframes.get(0);
|
||||
mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);
|
||||
mInterpolator = mLastKeyframe.getInterpolator();
|
||||
}
|
||||
|
||||
public static KeyframeSet ofInt(int... values) {
|
||||
int numKeyframes = values.length;
|
||||
IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)];
|
||||
if (numKeyframes == 1) {
|
||||
keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f);
|
||||
keyframes[1] = (IntKeyframe) Keyframe.ofInt(1f, values[0]);
|
||||
} else {
|
||||
keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f, values[0]);
|
||||
for (int i = 1; i < numKeyframes; ++i) {
|
||||
keyframes[i] = (IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]);
|
||||
}
|
||||
}
|
||||
return new IntKeyframeSet(keyframes);
|
||||
}
|
||||
|
||||
public static KeyframeSet ofFloat(float... values) {
|
||||
int numKeyframes = values.length;
|
||||
FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
|
||||
if (numKeyframes == 1) {
|
||||
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
|
||||
keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
|
||||
} else {
|
||||
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
|
||||
for (int i = 1; i < numKeyframes; ++i) {
|
||||
keyframes[i] = (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
|
||||
}
|
||||
}
|
||||
return new FloatKeyframeSet(keyframes);
|
||||
}
|
||||
|
||||
public static KeyframeSet ofKeyframe(Keyframe... keyframes) {
|
||||
// if all keyframes of same primitive type, create the appropriate KeyframeSet
|
||||
int numKeyframes = keyframes.length;
|
||||
boolean hasFloat = false;
|
||||
boolean hasInt = false;
|
||||
boolean hasOther = false;
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
if (keyframes[i] instanceof FloatKeyframe) {
|
||||
hasFloat = true;
|
||||
} else if (keyframes[i] instanceof IntKeyframe) {
|
||||
hasInt = true;
|
||||
} else {
|
||||
hasOther = true;
|
||||
}
|
||||
}
|
||||
if (hasFloat && !hasInt && !hasOther) {
|
||||
FloatKeyframe floatKeyframes[] = new FloatKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
floatKeyframes[i] = (FloatKeyframe) keyframes[i];
|
||||
}
|
||||
return new FloatKeyframeSet(floatKeyframes);
|
||||
} else if (hasInt && !hasFloat && !hasOther) {
|
||||
IntKeyframe intKeyframes[] = new IntKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
intKeyframes[i] = (IntKeyframe) keyframes[i];
|
||||
}
|
||||
return new IntKeyframeSet(intKeyframes);
|
||||
} else {
|
||||
return new KeyframeSet(keyframes);
|
||||
}
|
||||
}
|
||||
|
||||
public static KeyframeSet ofObject(Object... values) {
|
||||
int numKeyframes = values.length;
|
||||
ObjectKeyframe keyframes[] = new ObjectKeyframe[Math.max(numKeyframes,2)];
|
||||
if (numKeyframes == 1) {
|
||||
keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f);
|
||||
keyframes[1] = (ObjectKeyframe) Keyframe.ofObject(1f, values[0]);
|
||||
} else {
|
||||
keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f, values[0]);
|
||||
for (int i = 1; i < numKeyframes; ++i) {
|
||||
keyframes[i] = (ObjectKeyframe) Keyframe.ofObject((float) i / (numKeyframes - 1), values[i]);
|
||||
}
|
||||
}
|
||||
return new KeyframeSet(keyframes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the TypeEvaluator to be used when calculating animated values. This object
|
||||
* is required only for KeyframeSets that are not either IntKeyframeSet or FloatKeyframeSet,
|
||||
* both of which assume their own evaluator to speed up calculations with those primitive
|
||||
* types.
|
||||
*
|
||||
* @param evaluator The TypeEvaluator to be used to calculate animated values.
|
||||
*/
|
||||
public void setEvaluator(TypeEvaluator evaluator) {
|
||||
mEvaluator = evaluator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyframeSet clone() {
|
||||
ArrayList<Keyframe> keyframes = mKeyframes;
|
||||
int numKeyframes = mKeyframes.size();
|
||||
Keyframe[] newKeyframes = new Keyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
newKeyframes[i] = keyframes.get(i).clone();
|
||||
}
|
||||
KeyframeSet newSet = new KeyframeSet(newKeyframes);
|
||||
return newSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the animated value, given the elapsed fraction of the animation (interpolated by the
|
||||
* animation's interpolator) and the evaluator used to calculate in-between values. This
|
||||
* function maps the input fraction to the appropriate keyframe interval and a fraction
|
||||
* between them and returns the interpolated value. Note that the input fraction may fall
|
||||
* outside the [0-1] bounds, if the animation's interpolator made that happen (e.g., a
|
||||
* spring interpolation that might send the fraction past 1.0). We handle this situation by
|
||||
* just using the two keyframes at the appropriate end when the value is outside those bounds.
|
||||
*
|
||||
* @param fraction The elapsed fraction of the animation
|
||||
* @return The animated value.
|
||||
*/
|
||||
public Object getValue(float fraction) {
|
||||
|
||||
// Special-case optimization for the common case of only two keyframes
|
||||
if (mNumKeyframes == 2) {
|
||||
if (mInterpolator != null) {
|
||||
fraction = mInterpolator.getInterpolation(fraction);
|
||||
}
|
||||
return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(),
|
||||
mLastKeyframe.getValue());
|
||||
}
|
||||
if (fraction <= 0f) {
|
||||
final Keyframe nextKeyframe = mKeyframes.get(1);
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
final float prevFraction = mFirstKeyframe.getFraction();
|
||||
float intervalFraction = (fraction - prevFraction) /
|
||||
(nextKeyframe.getFraction() - prevFraction);
|
||||
return mEvaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(),
|
||||
nextKeyframe.getValue());
|
||||
} else if (fraction >= 1f) {
|
||||
final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
|
||||
final /*Time*/Interpolator interpolator = mLastKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
final float prevFraction = prevKeyframe.getFraction();
|
||||
float intervalFraction = (fraction - prevFraction) /
|
||||
(mLastKeyframe.getFraction() - prevFraction);
|
||||
return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
|
||||
mLastKeyframe.getValue());
|
||||
}
|
||||
Keyframe prevKeyframe = mFirstKeyframe;
|
||||
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||
Keyframe nextKeyframe = mKeyframes.get(i);
|
||||
if (fraction < nextKeyframe.getFraction()) {
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
final float prevFraction = prevKeyframe.getFraction();
|
||||
float intervalFraction = (fraction - prevFraction) /
|
||||
(nextKeyframe.getFraction() - prevFraction);
|
||||
return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
|
||||
nextKeyframe.getValue());
|
||||
}
|
||||
prevKeyframe = nextKeyframe;
|
||||
}
|
||||
// shouldn't reach here
|
||||
return mLastKeyframe.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String returnVal = " ";
|
||||
for (int i = 0; i < mNumKeyframes; ++i) {
|
||||
returnVal += mKeyframes.get(i).getValue() + " ";
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
}
|
@ -1,491 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
import android.util.Log;
|
||||
//import android.util.Property;
|
||||
|
||||
//import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* This subclass of {@link ValueAnimator} provides support for animating properties on target objects.
|
||||
* The constructors of this class take parameters to define the target object that will be animated
|
||||
* as well as the name of the property that will be animated. Appropriate set/get functions
|
||||
* are then determined internally and the animation will call these functions as necessary to
|
||||
* animate the property.
|
||||
*
|
||||
* @see #setPropertyName(String)
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public final class ObjectAnimator extends ValueAnimator {
|
||||
private static final boolean DBG = false;
|
||||
|
||||
// The target object on which the property exists, set in the constructor
|
||||
private Object mTarget;
|
||||
|
||||
private String mPropertyName;
|
||||
|
||||
//private Property mProperty;
|
||||
|
||||
/**
|
||||
* Sets the name of the property that will be animated. This name is used to derive
|
||||
* a setter function that will be called to set animated values.
|
||||
* For example, a property name of <code>foo</code> will result
|
||||
* in a call to the function <code>setFoo()</code> on the target object. If either
|
||||
* <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
|
||||
* also be derived and called.
|
||||
*
|
||||
* <p>For best performance of the mechanism that calls the setter function determined by the
|
||||
* name of the property being animated, use <code>float</code> or <code>int</code> typed values,
|
||||
* and make the setter function for those properties have a <code>void</code> return value. This
|
||||
* will cause the code to take an optimized path for these constrained circumstances. Other
|
||||
* property types and return types will work, but will have more overhead in processing
|
||||
* the requests due to normal reflection mechanisms.</p>
|
||||
*
|
||||
* <p>Note that the setter function derived from this property name
|
||||
* must take the same parameter type as the
|
||||
* <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
|
||||
* the setter function will fail.</p>
|
||||
*
|
||||
* <p>If this ObjectAnimator has been set up to animate several properties together,
|
||||
* using more than one PropertyValuesHolder objects, then setting the propertyName simply
|
||||
* sets the propertyName in the first of those PropertyValuesHolder objects.</p>
|
||||
*
|
||||
* @param propertyName The name of the property being animated. Should not be null.
|
||||
*/
|
||||
public void setPropertyName(String propertyName) {
|
||||
// mValues could be null if this is being constructed piecemeal. Just record the
|
||||
// propertyName to be used later when setValues() is called if so.
|
||||
if (mValues != null) {
|
||||
PropertyValuesHolder valuesHolder = mValues[0];
|
||||
String oldName = valuesHolder.getPropertyName();
|
||||
valuesHolder.setPropertyName(propertyName);
|
||||
mValuesMap.remove(oldName);
|
||||
mValuesMap.put(propertyName, valuesHolder);
|
||||
}
|
||||
mPropertyName = propertyName;
|
||||
// New property/values/target should cause re-initialization prior to starting
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the property that will be animated. Property objects will take precedence over
|
||||
* properties specified by the {@link #setPropertyName(String)} method. Animations should
|
||||
* be set up to use one or the other, not both.
|
||||
*
|
||||
* @param property The property being animated. Should not be null.
|
||||
*/
|
||||
//public void setProperty(Property property) {
|
||||
// // mValues could be null if this is being constructed piecemeal. Just record the
|
||||
// // propertyName to be used later when setValues() is called if so.
|
||||
// if (mValues != null) {
|
||||
// PropertyValuesHolder valuesHolder = mValues[0];
|
||||
// String oldName = valuesHolder.getPropertyName();
|
||||
// valuesHolder.setProperty(property);
|
||||
// mValuesMap.remove(oldName);
|
||||
// mValuesMap.put(mPropertyName, valuesHolder);
|
||||
// }
|
||||
// if (mProperty != null) {
|
||||
// mPropertyName = property.getName();
|
||||
// }
|
||||
// mProperty = property;
|
||||
// // New property/values/target should cause re-initialization prior to starting
|
||||
// mInitialized = false;
|
||||
//}
|
||||
|
||||
/**
|
||||
* Gets the name of the property that will be animated. This name will be used to derive
|
||||
* a setter function that will be called to set animated values.
|
||||
* For example, a property name of <code>foo</code> will result
|
||||
* in a call to the function <code>setFoo()</code> on the target object. If either
|
||||
* <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
|
||||
* also be derived and called.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return mPropertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ObjectAnimator object. This default constructor is primarily for
|
||||
* use internally; the other constructors which take parameters are more generally
|
||||
* useful.
|
||||
*/
|
||||
public ObjectAnimator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Private utility constructor that initializes the target object and name of the
|
||||
* property being animated.
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
*/
|
||||
private ObjectAnimator(Object target, String propertyName) {
|
||||
mTarget = target;
|
||||
setPropertyName(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private utility constructor that initializes the target object and property being animated.
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
*/
|
||||
//private <T> ObjectAnimator(T target, Property<T, ?> property) {
|
||||
// mTarget = target;
|
||||
// setProperty(property);
|
||||
//}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between int values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
|
||||
anim.setIntValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between int values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
//public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> property, int... values) {
|
||||
// ObjectAnimator anim = new ObjectAnimator(target, property);
|
||||
// anim.setIntValues(values);
|
||||
// return anim;
|
||||
//}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between float values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
|
||||
anim.setFloatValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between float values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
//public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property,
|
||||
// float... values) {
|
||||
// ObjectAnimator anim = new ObjectAnimator(target, property);
|
||||
// anim.setFloatValues(values);
|
||||
// return anim;
|
||||
//}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between Object values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
* @param evaluator A TypeEvaluator that will be called on each animation frame to
|
||||
* provide the necessary interpolation between the Object values to derive the animated
|
||||
* value.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofObject(Object target, String propertyName,
|
||||
TypeEvaluator evaluator, Object... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
|
||||
anim.setObjectValues(values);
|
||||
anim.setEvaluator(evaluator);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between Object values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
* @param evaluator A TypeEvaluator that will be called on each animation frame to
|
||||
* provide the necessary interpolation between the Object values to derive the animated
|
||||
* value.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
//public static <T, V> ObjectAnimator ofObject(T target, Property<T, V> property,
|
||||
// TypeEvaluator<V> evaluator, V... values) {
|
||||
// ObjectAnimator anim = new ObjectAnimator(target, property);
|
||||
// anim.setObjectValues(values);
|
||||
// anim.setEvaluator(evaluator);
|
||||
// return anim;
|
||||
//}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between the sets of values specified
|
||||
* in <code>PropertyValueHolder</code> objects. This variant should be used when animating
|
||||
* several properties at once with the same ObjectAnimator, since PropertyValuesHolder allows
|
||||
* you to associate a set of animation values with a property name.
|
||||
*
|
||||
* @param target The object whose property is to be animated. Depending on how the
|
||||
* PropertyValuesObjects were constructed, the target object should either have the {@link
|
||||
* android.util.Property} objects used to construct the PropertyValuesHolder objects or (if the
|
||||
* PropertyValuesHOlder objects were created with property names) the target object should have
|
||||
* public methods on it called <code>setName()</code>, where <code>name</code> is the name of
|
||||
* the property passed in as the <code>propertyName</code> parameter for each of the
|
||||
* PropertyValuesHolder objects.
|
||||
* @param values A set of PropertyValuesHolder objects whose values will be animated between
|
||||
* over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofPropertyValuesHolder(Object target,
|
||||
PropertyValuesHolder... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator();
|
||||
anim.mTarget = target;
|
||||
anim.setValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIntValues(int... values) {
|
||||
if (mValues == null || mValues.length == 0) {
|
||||
// No values yet - this animator is being constructed piecemeal. Init the values with
|
||||
// whatever the current propertyName is
|
||||
//if (mProperty != null) {
|
||||
// setValues(PropertyValuesHolder.ofInt(mProperty, values));
|
||||
//} else {
|
||||
setValues(PropertyValuesHolder.ofInt(mPropertyName, values));
|
||||
//}
|
||||
} else {
|
||||
super.setIntValues(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFloatValues(float... values) {
|
||||
if (mValues == null || mValues.length == 0) {
|
||||
// No values yet - this animator is being constructed piecemeal. Init the values with
|
||||
// whatever the current propertyName is
|
||||
//if (mProperty != null) {
|
||||
// setValues(PropertyValuesHolder.ofFloat(mProperty, values));
|
||||
//} else {
|
||||
setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
|
||||
//}
|
||||
} else {
|
||||
super.setFloatValues(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObjectValues(Object... values) {
|
||||
if (mValues == null || mValues.length == 0) {
|
||||
// No values yet - this animator is being constructed piecemeal. Init the values with
|
||||
// whatever the current propertyName is
|
||||
//if (mProperty != null) {
|
||||
// setValues(PropertyValuesHolder.ofObject(mProperty, (TypeEvaluator)null, values));
|
||||
//} else {
|
||||
setValues(PropertyValuesHolder.ofObject(mPropertyName, (TypeEvaluator)null, values));
|
||||
//}
|
||||
} else {
|
||||
super.setObjectValues(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (DBG) {
|
||||
Log.d("ObjectAnimator", "Anim target, duration: " + mTarget + ", " + getDuration());
|
||||
for (int i = 0; i < mValues.length; ++i) {
|
||||
PropertyValuesHolder pvh = mValues[i];
|
||||
ArrayList<Keyframe> keyframes = pvh.mKeyframeSet.mKeyframes;
|
||||
Log.d("ObjectAnimator", " Values[" + i + "]: " +
|
||||
pvh.getPropertyName() + ", " + keyframes.get(0).getValue() + ", " +
|
||||
keyframes.get(pvh.mKeyframeSet.mNumKeyframes - 1).getValue());
|
||||
}
|
||||
}
|
||||
super.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called immediately before processing the first animation
|
||||
* frame of an animation. If there is a nonzero <code>startDelay</code>, the
|
||||
* function is called after that delay ends.
|
||||
* It takes care of the final initialization steps for the
|
||||
* animation. This includes setting mEvaluator, if the user has not yet
|
||||
* set it up, and the setter/getter methods, if the user did not supply
|
||||
* them.
|
||||
*
|
||||
* <p>Overriders of this method should call the superclass method to cause
|
||||
* internal mechanisms to be set up correctly.</p>
|
||||
*/
|
||||
@Override
|
||||
void initAnimation() {
|
||||
if (!mInitialized) {
|
||||
// mValueType may change due to setter/getter setup; do this before calling super.init(),
|
||||
// which uses mValueType to set up the default type evaluator.
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setupSetterAndGetter(mTarget);
|
||||
}
|
||||
super.initAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the length of the animation. The default duration is 300 milliseconds.
|
||||
*
|
||||
* @param duration The length of the animation, in milliseconds.
|
||||
* @return ObjectAnimator The object called with setDuration(). This return
|
||||
* value makes it easier to compose statements together that construct and then set the
|
||||
* duration, as in
|
||||
* <code>ObjectAnimator.ofInt(target, propertyName, 0, 10).setDuration(500).start()</code>.
|
||||
*/
|
||||
@Override
|
||||
public ObjectAnimator setDuration(long duration) {
|
||||
super.setDuration(duration);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The target object whose property will be animated by this animation
|
||||
*
|
||||
* @return The object being animated
|
||||
*/
|
||||
public Object getTarget() {
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target object whose property will be animated by this animation
|
||||
*
|
||||
* @param target The object being animated
|
||||
*/
|
||||
@Override
|
||||
public void setTarget(Object target) {
|
||||
if (mTarget != target) {
|
||||
final Object oldTarget = mTarget;
|
||||
mTarget = target;
|
||||
if (oldTarget != null && target != null && oldTarget.getClass() == target.getClass()) {
|
||||
return;
|
||||
}
|
||||
// New target type should cause re-initialization prior to starting
|
||||
mInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupStartValues() {
|
||||
initAnimation();
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setupStartValue(mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupEndValues() {
|
||||
initAnimation();
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setupEndValue(mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called with the elapsed fraction of the animation during every
|
||||
* animation frame. This function turns the elapsed fraction into an interpolated fraction
|
||||
* and then into an animated value (from the evaluator. The function is called mostly during
|
||||
* animation updates, but it is also called when the <code>end()</code>
|
||||
* function is called, to set the final value on the property.
|
||||
*
|
||||
* <p>Overrides of this method must call the superclass to perform the calculation
|
||||
* of the animated value.</p>
|
||||
*
|
||||
* @param fraction The elapsed fraction of the animation.
|
||||
*/
|
||||
@Override
|
||||
void animateValue(float fraction) {
|
||||
super.animateValue(fraction);
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setAnimatedValue(mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectAnimator clone() {
|
||||
final ObjectAnimator anim = (ObjectAnimator) super.clone();
|
||||
return anim;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String returnVal = "ObjectAnimator@" + Integer.toHexString(hashCode()) + ", target " +
|
||||
mTarget;
|
||||
if (mValues != null) {
|
||||
for (int i = 0; i < mValues.length; ++i) {
|
||||
returnVal += "\n " + mValues[i].toString();
|
||||
}
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* Interface for use with the {@link ValueAnimator#setEvaluator(TypeEvaluator)} function. Evaluators
|
||||
* allow developers to create animations on arbitrary property types, by allowing them to supply
|
||||
* custom evaulators for types that are not automatically understood and used by the animation
|
||||
* system.
|
||||
*
|
||||
* @see ValueAnimator#setEvaluator(TypeEvaluator)
|
||||
*/
|
||||
public interface TypeEvaluator<T> {
|
||||
|
||||
/**
|
||||
* This function returns the result of linearly interpolating the start and end values, with
|
||||
* <code>fraction</code> representing the proportion between the start and end values. The
|
||||
* calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
|
||||
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
|
||||
* and <code>t</code> is <code>fraction</code>.
|
||||
*
|
||||
* @param fraction The fraction from the starting to the ending values
|
||||
* @param startValue The start value.
|
||||
* @param endValue The end value.
|
||||
* @return A linear interpolation between the start and end values, given the
|
||||
* <code>fraction</code> parameter.
|
||||
*/
|
||||
public T evaluate(float fraction, T startValue, T endValue);
|
||||
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
package com.actionbarsherlock.internal.nineoldandroids.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy;
|
||||
|
||||
public abstract class NineViewGroup extends ViewGroup {
|
||||
private final AnimatorProxy mProxy;
|
||||
|
||||
public NineViewGroup(Context context) {
|
||||
super(context);
|
||||
mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
|
||||
}
|
||||
public NineViewGroup(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
|
||||
}
|
||||
public NineViewGroup(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
if (mProxy != null) {
|
||||
if (visibility == GONE) {
|
||||
clearAnimation();
|
||||
} else if (visibility == VISIBLE) {
|
||||
setAnimation(mProxy);
|
||||
}
|
||||
}
|
||||
super.setVisibility(visibility);
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
return mProxy.getAlpha();
|
||||
} else {
|
||||
return super.getAlpha();
|
||||
}
|
||||
}
|
||||
public void setAlpha(float alpha) {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
mProxy.setAlpha(alpha);
|
||||
} else {
|
||||
super.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
public float getTranslationX() {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
return mProxy.getTranslationX();
|
||||
} else {
|
||||
return super.getTranslationX();
|
||||
}
|
||||
}
|
||||
public void setTranslationX(float translationX) {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
mProxy.setTranslationX(translationX);
|
||||
} else {
|
||||
super.setTranslationX(translationX);
|
||||
}
|
||||
}
|
||||
public float getTranslationY() {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
return mProxy.getTranslationY();
|
||||
} else {
|
||||
return super.getTranslationY();
|
||||
}
|
||||
}
|
||||
public void setTranslationY(float translationY) {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
mProxy.setTranslationY(translationY);
|
||||
} else {
|
||||
super.setTranslationY(translationY);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,212 +0,0 @@
|
||||
package com.actionbarsherlock.internal.nineoldandroids.view.animation;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.WeakHashMap;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.util.FloatMath;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Transformation;
|
||||
|
||||
public final class AnimatorProxy extends Animation {
|
||||
public static final boolean NEEDS_PROXY = Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB;
|
||||
|
||||
private static final WeakHashMap<View, AnimatorProxy> PROXIES =
|
||||
new WeakHashMap<View, AnimatorProxy>();
|
||||
|
||||
public static AnimatorProxy wrap(View view) {
|
||||
AnimatorProxy proxy = PROXIES.get(view);
|
||||
if (proxy == null) {
|
||||
proxy = new AnimatorProxy(view);
|
||||
PROXIES.put(view, proxy);
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
private final WeakReference<View> mView;
|
||||
|
||||
private float mAlpha = 1;
|
||||
private float mScaleX = 1;
|
||||
private float mScaleY = 1;
|
||||
private float mTranslationX;
|
||||
private float mTranslationY;
|
||||
|
||||
private final RectF mBefore = new RectF();
|
||||
private final RectF mAfter = new RectF();
|
||||
private final Matrix mTempMatrix = new Matrix();
|
||||
|
||||
private AnimatorProxy(View view) {
|
||||
setDuration(0); //perform transformation immediately
|
||||
setFillAfter(true); //persist transformation beyond duration
|
||||
view.setAnimation(this);
|
||||
mView = new WeakReference<View>(view);
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
return mAlpha;
|
||||
}
|
||||
public void setAlpha(float alpha) {
|
||||
if (mAlpha != alpha) {
|
||||
mAlpha = alpha;
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
view.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
public float getScaleX() {
|
||||
return mScaleX;
|
||||
}
|
||||
public void setScaleX(float scaleX) {
|
||||
if (mScaleX != scaleX) {
|
||||
prepareForUpdate();
|
||||
mScaleX = scaleX;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
public float getScaleY() {
|
||||
return mScaleY;
|
||||
}
|
||||
public void setScaleY(float scaleY) {
|
||||
if (mScaleY != scaleY) {
|
||||
prepareForUpdate();
|
||||
mScaleY = scaleY;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
public int getScrollX() {
|
||||
View view = mView.get();
|
||||
if (view == null) {
|
||||
return 0;
|
||||
}
|
||||
return view.getScrollX();
|
||||
}
|
||||
public void setScrollX(int value) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
view.scrollTo(value, view.getScrollY());
|
||||
}
|
||||
}
|
||||
public int getScrollY() {
|
||||
View view = mView.get();
|
||||
if (view == null) {
|
||||
return 0;
|
||||
}
|
||||
return view.getScrollY();
|
||||
}
|
||||
public void setScrollY(int value) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
view.scrollTo(view.getScrollY(), value);
|
||||
}
|
||||
}
|
||||
|
||||
public float getTranslationX() {
|
||||
return mTranslationX;
|
||||
}
|
||||
public void setTranslationX(float translationX) {
|
||||
if (mTranslationX != translationX) {
|
||||
prepareForUpdate();
|
||||
mTranslationX = translationX;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
public float getTranslationY() {
|
||||
return mTranslationY;
|
||||
}
|
||||
public void setTranslationY(float translationY) {
|
||||
if (mTranslationY != translationY) {
|
||||
prepareForUpdate();
|
||||
mTranslationY = translationY;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareForUpdate() {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
computeRect(mBefore, view);
|
||||
}
|
||||
}
|
||||
private void invalidateAfterUpdate() {
|
||||
View view = mView.get();
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
View parent = (View)view.getParent();
|
||||
if (parent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
view.setAnimation(this);
|
||||
|
||||
final RectF after = mAfter;
|
||||
computeRect(after, view);
|
||||
after.union(mBefore);
|
||||
|
||||
parent.invalidate(
|
||||
(int) FloatMath.floor(after.left),
|
||||
(int) FloatMath.floor(after.top),
|
||||
(int) FloatMath.ceil(after.right),
|
||||
(int) FloatMath.ceil(after.bottom));
|
||||
}
|
||||
|
||||
private void computeRect(final RectF r, View view) {
|
||||
// compute current rectangle according to matrix transformation
|
||||
final float w = view.getWidth();
|
||||
final float h = view.getHeight();
|
||||
|
||||
// use a rectangle at 0,0 to make sure we don't run into issues with scaling
|
||||
r.set(0, 0, w, h);
|
||||
|
||||
final Matrix m = mTempMatrix;
|
||||
m.reset();
|
||||
transformMatrix(m, view);
|
||||
mTempMatrix.mapRect(r);
|
||||
|
||||
r.offset(view.getLeft(), view.getTop());
|
||||
|
||||
// Straighten coords if rotations flipped them
|
||||
if (r.right < r.left) {
|
||||
final float f = r.right;
|
||||
r.right = r.left;
|
||||
r.left = f;
|
||||
}
|
||||
if (r.bottom < r.top) {
|
||||
final float f = r.top;
|
||||
r.top = r.bottom;
|
||||
r.bottom = f;
|
||||
}
|
||||
}
|
||||
|
||||
private void transformMatrix(Matrix m, View view) {
|
||||
final float w = view.getWidth();
|
||||
final float h = view.getHeight();
|
||||
|
||||
final float sX = mScaleX;
|
||||
final float sY = mScaleY;
|
||||
if ((sX != 1.0f) || (sY != 1.0f)) {
|
||||
final float deltaSX = ((sX * w) - w) / 2f;
|
||||
final float deltaSY = ((sY * h) - h) / 2f;
|
||||
m.postScale(sX, sY);
|
||||
m.postTranslate(-deltaSX, -deltaSY);
|
||||
}
|
||||
m.postTranslate(mTranslationX, mTranslationY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransformation(float interpolatedTime, Transformation t) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
t.setAlpha(mAlpha);
|
||||
transformMatrix(t.getMatrix(), view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
/* Do nothing. */
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package com.actionbarsherlock.internal.nineoldandroids.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy;
|
||||
|
||||
public class NineFrameLayout extends FrameLayout {
|
||||
private final AnimatorProxy mProxy;
|
||||
|
||||
public NineFrameLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
if (mProxy != null) {
|
||||
if (visibility == GONE) {
|
||||
clearAnimation();
|
||||
} else if (visibility == VISIBLE) {
|
||||
setAnimation(mProxy);
|
||||
}
|
||||
}
|
||||
super.setVisibility(visibility);
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
return mProxy.getAlpha();
|
||||
} else {
|
||||
return super.getAlpha();
|
||||
}
|
||||
}
|
||||
public void setAlpha(float alpha) {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
mProxy.setAlpha(alpha);
|
||||
} else {
|
||||
super.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
public float getTranslationY() {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
return mProxy.getTranslationY();
|
||||
} else {
|
||||
return super.getTranslationY();
|
||||
}
|
||||
}
|
||||
public void setTranslationY(float translationY) {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
mProxy.setTranslationY(translationY);
|
||||
} else {
|
||||
super.setTranslationY(translationY);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
package com.actionbarsherlock.internal.nineoldandroids.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.widget.HorizontalScrollView;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy;
|
||||
|
||||
public class NineHorizontalScrollView extends HorizontalScrollView {
|
||||
private final AnimatorProxy mProxy;
|
||||
|
||||
public NineHorizontalScrollView(Context context) {
|
||||
super(context);
|
||||
mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
if (mProxy != null) {
|
||||
if (visibility == GONE) {
|
||||
clearAnimation();
|
||||
} else if (visibility == VISIBLE) {
|
||||
setAnimation(mProxy);
|
||||
}
|
||||
}
|
||||
super.setVisibility(visibility);
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
return mProxy.getAlpha();
|
||||
} else {
|
||||
return super.getAlpha();
|
||||
}
|
||||
}
|
||||
public void setAlpha(float alpha) {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
mProxy.setAlpha(alpha);
|
||||
} else {
|
||||
super.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package com.actionbarsherlock.internal.nineoldandroids.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy;
|
||||
|
||||
public class NineLinearLayout extends LinearLayout {
|
||||
private final AnimatorProxy mProxy;
|
||||
|
||||
public NineLinearLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
if (mProxy != null) {
|
||||
if (visibility == GONE) {
|
||||
clearAnimation();
|
||||
} else if (visibility == VISIBLE) {
|
||||
setAnimation(mProxy);
|
||||
}
|
||||
}
|
||||
super.setVisibility(visibility);
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
return mProxy.getAlpha();
|
||||
} else {
|
||||
return super.getAlpha();
|
||||
}
|
||||
}
|
||||
public void setAlpha(float alpha) {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
mProxy.setAlpha(alpha);
|
||||
} else {
|
||||
super.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
public float getTranslationX() {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
return mProxy.getTranslationX();
|
||||
} else {
|
||||
return super.getTranslationX();
|
||||
}
|
||||
}
|
||||
public void setTranslationX(float translationX) {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
mProxy.setTranslationX(translationX);
|
||||
} else {
|
||||
super.setTranslationX(translationX);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
package com.actionbarsherlock.internal.view;
|
||||
|
||||
import com.actionbarsherlock.internal.view.menu.SubMenuWrapper;
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import android.view.View;
|
||||
|
||||
public class ActionProviderWrapper extends android.view.ActionProvider {
|
||||
private final ActionProvider mProvider;
|
||||
|
||||
|
||||
public ActionProviderWrapper(ActionProvider provider) {
|
||||
super(null/*TODO*/); //XXX this *should* be unused
|
||||
mProvider = provider;
|
||||
}
|
||||
|
||||
|
||||
public ActionProvider unwrap() {
|
||||
return mProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateActionView() {
|
||||
return mProvider.onCreateActionView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSubMenu() {
|
||||
return mProvider.hasSubMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPerformDefaultAction() {
|
||||
return mProvider.onPerformDefaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareSubMenu(android.view.SubMenu subMenu) {
|
||||
mProvider.onPrepareSubMenu(new SubMenuWrapper(subMenu));
|
||||
}
|
||||
}
|
@ -1,148 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.actionbarsherlock.internal.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import com.actionbarsherlock.internal.view.menu.MenuBuilder;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuPopupHelper;
|
||||
import com.actionbarsherlock.internal.view.menu.SubMenuBuilder;
|
||||
import com.actionbarsherlock.internal.widget.ActionBarContextView;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
public class StandaloneActionMode extends ActionMode implements MenuBuilder.Callback {
|
||||
private Context mContext;
|
||||
private ActionBarContextView mContextView;
|
||||
private ActionMode.Callback mCallback;
|
||||
private WeakReference<View> mCustomView;
|
||||
private boolean mFinished;
|
||||
private boolean mFocusable;
|
||||
|
||||
private MenuBuilder mMenu;
|
||||
|
||||
public StandaloneActionMode(Context context, ActionBarContextView view,
|
||||
ActionMode.Callback callback, boolean isFocusable) {
|
||||
mContext = context;
|
||||
mContextView = view;
|
||||
mCallback = callback;
|
||||
|
||||
mMenu = new MenuBuilder(context).setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
mMenu.setCallback(this);
|
||||
mFocusable = isFocusable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(CharSequence title) {
|
||||
mContextView.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(CharSequence subtitle) {
|
||||
mContextView.setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(int resId) {
|
||||
setTitle(mContext.getString(resId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(int resId) {
|
||||
setSubtitle(mContext.getString(resId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomView(View view) {
|
||||
mContextView.setCustomView(view);
|
||||
mCustomView = view != null ? new WeakReference<View>(view) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
mCallback.onPrepareActionMode(this, mMenu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
if (mFinished) {
|
||||
return;
|
||||
}
|
||||
mFinished = true;
|
||||
|
||||
mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
|
||||
mCallback.onDestroyActionMode(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Menu getMenu() {
|
||||
return mMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitle() {
|
||||
return mContextView.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSubtitle() {
|
||||
return mContextView.getSubtitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getCustomView() {
|
||||
return mCustomView != null ? mCustomView.get() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuInflater getMenuInflater() {
|
||||
return new MenuInflater(mContext);
|
||||
}
|
||||
|
||||
public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
|
||||
return mCallback.onActionItemClicked(this, item);
|
||||
}
|
||||
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||||
}
|
||||
|
||||
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
|
||||
if (!subMenu.hasVisibleItems()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
new MenuPopupHelper(mContext, subMenu).show();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onCloseSubMenu(SubMenuBuilder menu) {
|
||||
}
|
||||
|
||||
public void onMenuModeChange(MenuBuilder menu) {
|
||||
invalidate();
|
||||
mContextView.showOverflowMenu();
|
||||
}
|
||||
|
||||
public boolean isUiFocusable() {
|
||||
return mFocusable;
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package com.actionbarsherlock.internal.view;
|
||||
|
||||
public interface View_HasStateListenerSupport {
|
||||
void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener);
|
||||
void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener);
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package com.actionbarsherlock.internal.view;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
public interface View_OnAttachStateChangeListener {
|
||||
void onViewAttachedToWindow(View v);
|
||||
void onViewDetachedFromWindow(View v);
|
||||
}
|
@ -1,264 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.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 com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.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();
|
||||
}
|
||||
}
|
@ -1,278 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.View;
|
||||
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ActionMenuItem implements MenuItem {
|
||||
private final int mId;
|
||||
private final int mGroup;
|
||||
//UNUSED 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;
|
||||
//UNUSED private int mIconResId = NO_ICON;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private MenuItem.OnMenuItemClickListener mClickListener;
|
||||
|
||||
//UNUSED 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;
|
||||
//UNUSED 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;
|
||||
//UNUSED mIconResId = NO_ICON;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setIcon(int iconRes) {
|
||||
//UNUSED 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;
|
||||
}
|
||||
|
||||
public void setShowAsAction(int show) {
|
||||
// Do nothing. ActionMenuItems always show as action buttons.
|
||||
}
|
||||
|
||||
public MenuItem setActionView(View actionView) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public View getActionView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionView(int resId) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionProvider getActionProvider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionProvider(ActionProvider actionProvider) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShowAsActionFlags(int actionEnum) {
|
||||
setShowAsAction(actionEnum);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expandActionView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collapseActionView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActionViewExpanded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
|
||||
// No need to save the listener; ActionMenuItem does not support collapsing items.
|
||||
return this;
|
||||
}
|
||||
}
|
@ -1,295 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.view.View_HasStateListenerSupport;
|
||||
import com.actionbarsherlock.internal.view.View_OnAttachStateChangeListener;
|
||||
import com.actionbarsherlock.internal.widget.CapitalizingButton;
|
||||
|
||||
import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ActionMenuItemView extends LinearLayout
|
||||
implements MenuView.ItemView, View.OnClickListener, View.OnLongClickListener,
|
||||
ActionMenuView.ActionMenuChildView, View_HasStateListenerSupport {
|
||||
//UNUSED private static final String TAG = "ActionMenuItemView";
|
||||
|
||||
private MenuItemImpl mItemData;
|
||||
private CharSequence mTitle;
|
||||
private MenuBuilder.ItemInvoker mItemInvoker;
|
||||
|
||||
private ImageButton mImageButton;
|
||||
private CapitalizingButton mTextButton;
|
||||
private boolean mAllowTextWithIcon;
|
||||
private boolean mExpandedFormat;
|
||||
private int mMinWidth;
|
||||
|
||||
private final Set<View_OnAttachStateChangeListener> mListeners = new HashSet<View_OnAttachStateChangeListener>();
|
||||
|
||||
public ActionMenuItemView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ActionMenuItemView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public ActionMenuItemView(Context context, AttributeSet attrs, int defStyle) {
|
||||
//TODO super(context, attrs, defStyle);
|
||||
super(context, attrs);
|
||||
mAllowTextWithIcon = getResources_getBoolean(context,
|
||||
R.bool.abs__config_allowActionMenuItemTextWithIcon);
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
R.styleable.SherlockActionMenuItemView, 0, 0);
|
||||
mMinWidth = a.getDimensionPixelSize(
|
||||
R.styleable.SherlockActionMenuItemView_android_minWidth, 0);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
for (View_OnAttachStateChangeListener listener : mListeners) {
|
||||
listener.onViewAttachedToWindow(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
for (View_OnAttachStateChangeListener listener : mListeners) {
|
||||
listener.onViewDetachedFromWindow(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishInflate() {
|
||||
|
||||
mImageButton = (ImageButton) findViewById(R.id.abs__imageButton);
|
||||
mTextButton = (CapitalizingButton) findViewById(R.id.abs__textButton);
|
||||
mImageButton.setOnClickListener(this);
|
||||
mTextButton.setOnClickListener(this);
|
||||
mImageButton.setOnLongClickListener(this);
|
||||
setOnClickListener(this);
|
||||
setOnLongClickListener(this);
|
||||
}
|
||||
|
||||
public MenuItemImpl getItemData() {
|
||||
return mItemData;
|
||||
}
|
||||
|
||||
public void initialize(MenuItemImpl itemData, int menuType) {
|
||||
mItemData = itemData;
|
||||
|
||||
setIcon(itemData.getIcon());
|
||||
setTitle(itemData.getTitleForItemView(this)); // Title only takes effect if there is no icon
|
||||
setId(itemData.getItemId());
|
||||
|
||||
setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
|
||||
setEnabled(itemData.isEnabled());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
mImageButton.setEnabled(enabled);
|
||||
mTextButton.setEnabled(enabled);
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
if (mItemInvoker != null) {
|
||||
mItemInvoker.invokeItem(mItemData);
|
||||
}
|
||||
}
|
||||
|
||||
public void setItemInvoker(MenuBuilder.ItemInvoker invoker) {
|
||||
mItemInvoker = invoker;
|
||||
}
|
||||
|
||||
public boolean prefersCondensedTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setCheckable(boolean checkable) {
|
||||
// TODO Support checkable action items
|
||||
}
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
// TODO Support checkable action items
|
||||
}
|
||||
|
||||
public void setExpandedFormat(boolean expandedFormat) {
|
||||
if (mExpandedFormat != expandedFormat) {
|
||||
mExpandedFormat = expandedFormat;
|
||||
if (mItemData != null) {
|
||||
mItemData.actionFormatChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTextButtonVisibility() {
|
||||
boolean visible = !TextUtils.isEmpty(mTextButton.getText());
|
||||
visible &= mImageButton.getDrawable() == null ||
|
||||
(mItemData.showsTextAsAction() && (mAllowTextWithIcon || mExpandedFormat));
|
||||
|
||||
mTextButton.setVisibility(visible ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
public void setIcon(Drawable icon) {
|
||||
mImageButton.setImageDrawable(icon);
|
||||
if (icon != null) {
|
||||
mImageButton.setVisibility(VISIBLE);
|
||||
} else {
|
||||
mImageButton.setVisibility(GONE);
|
||||
}
|
||||
|
||||
updateTextButtonVisibility();
|
||||
}
|
||||
|
||||
public boolean hasText() {
|
||||
return mTextButton.getVisibility() != GONE;
|
||||
}
|
||||
|
||||
public void setShortcut(boolean showShortcut, char shortcutKey) {
|
||||
// Action buttons don't show text for shortcut keys.
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence title) {
|
||||
mTitle = title;
|
||||
|
||||
mTextButton.setTextCompat(mTitle);
|
||||
|
||||
setContentDescription(mTitle);
|
||||
updateTextButtonVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
|
||||
onPopulateAccessibilityEvent(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
super.onPopulateAccessibilityEvent(event);
|
||||
}
|
||||
final CharSequence cdesc = getContentDescription();
|
||||
if (!TextUtils.isEmpty(cdesc)) {
|
||||
event.getText().add(cdesc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchHoverEvent(MotionEvent event) {
|
||||
// Don't allow children to hover; we want this to be treated as a single component.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
return onHoverEvent(event);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean showsIcon() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean needsDividerBefore() {
|
||||
return hasText() && mItemData.getIcon() == null;
|
||||
}
|
||||
|
||||
public boolean needsDividerAfter() {
|
||||
return hasText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
if (hasText()) {
|
||||
// Don't show the cheat sheet for items that already show text.
|
||||
return false;
|
||||
}
|
||||
|
||||
final int[] screenPos = new int[2];
|
||||
final Rect displayFrame = new Rect();
|
||||
getLocationOnScreen(screenPos);
|
||||
getWindowVisibleDisplayFrame(displayFrame);
|
||||
|
||||
final Context context = getContext();
|
||||
final int width = getWidth();
|
||||
final int height = getHeight();
|
||||
final int midy = screenPos[1] + height / 2;
|
||||
final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
|
||||
|
||||
Toast cheatSheet = Toast.makeText(context, mItemData.getTitle(), Toast.LENGTH_SHORT);
|
||||
if (midy < displayFrame.height()) {
|
||||
// Show along the top; follow action buttons
|
||||
cheatSheet.setGravity(Gravity.TOP | Gravity.RIGHT,
|
||||
screenWidth - screenPos[0] - width / 2, height);
|
||||
} else {
|
||||
// Show along the bottom center
|
||||
cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
|
||||
}
|
||||
cheatSheet.show();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
final int specSize = MeasureSpec.getSize(widthMeasureSpec);
|
||||
final int oldMeasuredWidth = getMeasuredWidth();
|
||||
final int targetWidth = widthMode == MeasureSpec.AT_MOST ? Math.min(specSize, mMinWidth)
|
||||
: mMinWidth;
|
||||
|
||||
if (widthMode != MeasureSpec.EXACTLY && mMinWidth > 0 && oldMeasuredWidth < targetWidth) {
|
||||
// Remeasure at exactly the minimum width.
|
||||
super.onMeasure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY),
|
||||
heightMeasureSpec);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,714 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 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.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.view.SoundEffectConstants;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageButton;
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.view.View_HasStateListenerSupport;
|
||||
import com.actionbarsherlock.internal.view.View_OnAttachStateChangeListener;
|
||||
import com.actionbarsherlock.internal.view.menu.ActionMenuView.ActionMenuChildView;
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
/**
|
||||
* MenuPresenter for building action menus as seen in the action bar and action modes.
|
||||
*/
|
||||
public class ActionMenuPresenter extends BaseMenuPresenter
|
||||
implements ActionProvider.SubUiVisibilityListener {
|
||||
//UNUSED private static final String TAG = "ActionMenuPresenter";
|
||||
|
||||
private View mOverflowButton;
|
||||
private boolean mReserveOverflow;
|
||||
private boolean mReserveOverflowSet;
|
||||
private int mWidthLimit;
|
||||
private int mActionItemWidthLimit;
|
||||
private int mMaxItems;
|
||||
private boolean mMaxItemsSet;
|
||||
private boolean mStrictWidthLimit;
|
||||
private boolean mWidthLimitSet;
|
||||
private boolean mExpandedActionViewsExclusive;
|
||||
|
||||
private int mMinCellSize;
|
||||
|
||||
// Group IDs that have been added as actions - used temporarily, allocated here for reuse.
|
||||
private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray();
|
||||
|
||||
private View mScrapActionButtonView;
|
||||
|
||||
private OverflowPopup mOverflowPopup;
|
||||
private ActionButtonSubmenu mActionButtonPopup;
|
||||
|
||||
private OpenOverflowRunnable mPostedOpenRunnable;
|
||||
|
||||
final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
|
||||
int mOpenSubMenuId;
|
||||
|
||||
public ActionMenuPresenter(Context context) {
|
||||
super(context, R.layout.abs__action_menu_layout,
|
||||
R.layout.abs__action_menu_item_layout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initForMenu(Context context, MenuBuilder menu) {
|
||||
super.initForMenu(context, menu);
|
||||
|
||||
final Resources res = context.getResources();
|
||||
|
||||
if (!mReserveOverflowSet) {
|
||||
mReserveOverflow = reserveOverflow(mContext);
|
||||
}
|
||||
|
||||
if (!mWidthLimitSet) {
|
||||
mWidthLimit = res.getDisplayMetrics().widthPixels / 2;
|
||||
}
|
||||
|
||||
// Measure for initial configuration
|
||||
if (!mMaxItemsSet) {
|
||||
mMaxItems = getResources_getInteger(context, R.integer.abs__max_action_buttons);
|
||||
}
|
||||
|
||||
int width = mWidthLimit;
|
||||
if (mReserveOverflow) {
|
||||
if (mOverflowButton == null) {
|
||||
mOverflowButton = new OverflowMenuButton(mSystemContext);
|
||||
final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
mOverflowButton.measure(spec, spec);
|
||||
}
|
||||
width -= mOverflowButton.getMeasuredWidth();
|
||||
} else {
|
||||
mOverflowButton = null;
|
||||
}
|
||||
|
||||
mActionItemWidthLimit = width;
|
||||
|
||||
mMinCellSize = (int) (ActionMenuView.MIN_CELL_SIZE * res.getDisplayMetrics().density);
|
||||
|
||||
// Drop a scrap view as it may no longer reflect the proper context/config.
|
||||
mScrapActionButtonView = null;
|
||||
}
|
||||
|
||||
public static boolean reserveOverflow(Context context) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB);
|
||||
} else {
|
||||
return !HasPermanentMenuKey.get(context);
|
||||
}
|
||||
}
|
||||
|
||||
private static class HasPermanentMenuKey {
|
||||
public static boolean get(Context context) {
|
||||
return ViewConfiguration.get(context).hasPermanentMenuKey();
|
||||
}
|
||||
}
|
||||
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
if (!mMaxItemsSet) {
|
||||
mMaxItems = getResources_getInteger(mContext,
|
||||
R.integer.abs__max_action_buttons);
|
||||
if (mMenu != null) {
|
||||
mMenu.onItemsChanged(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setWidthLimit(int width, boolean strict) {
|
||||
mWidthLimit = width;
|
||||
mStrictWidthLimit = strict;
|
||||
mWidthLimitSet = true;
|
||||
}
|
||||
|
||||
public void setReserveOverflow(boolean reserveOverflow) {
|
||||
mReserveOverflow = reserveOverflow;
|
||||
mReserveOverflowSet = true;
|
||||
}
|
||||
|
||||
public void setItemLimit(int itemCount) {
|
||||
mMaxItems = itemCount;
|
||||
mMaxItemsSet = true;
|
||||
}
|
||||
|
||||
public void setExpandedActionViewsExclusive(boolean isExclusive) {
|
||||
mExpandedActionViewsExclusive = isExclusive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuView getMenuView(ViewGroup root) {
|
||||
MenuView result = super.getMenuView(root);
|
||||
((ActionMenuView) result).setPresenter(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
|
||||
View actionView = item.getActionView();
|
||||
if (actionView == null || item.hasCollapsibleActionView()) {
|
||||
if (!(convertView instanceof ActionMenuItemView)) {
|
||||
convertView = null;
|
||||
}
|
||||
actionView = super.getItemView(item, convertView, parent);
|
||||
}
|
||||
actionView.setVisibility(item.isActionViewExpanded() ? View.GONE : View.VISIBLE);
|
||||
|
||||
final ActionMenuView menuParent = (ActionMenuView) parent;
|
||||
final ViewGroup.LayoutParams lp = actionView.getLayoutParams();
|
||||
if (!menuParent.checkLayoutParams(lp)) {
|
||||
actionView.setLayoutParams(menuParent.generateLayoutParams(lp));
|
||||
}
|
||||
return actionView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItemView(MenuItemImpl item, MenuView.ItemView itemView) {
|
||||
itemView.initialize(item, 0);
|
||||
|
||||
final ActionMenuView menuView = (ActionMenuView) mMenuView;
|
||||
ActionMenuItemView actionItemView = (ActionMenuItemView) itemView;
|
||||
actionItemView.setItemInvoker(menuView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
|
||||
return item.isActionButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMenuView(boolean cleared) {
|
||||
super.updateMenuView(cleared);
|
||||
|
||||
if (mMenu != null) {
|
||||
final ArrayList<MenuItemImpl> actionItems = mMenu.getActionItems();
|
||||
final int count = actionItems.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final ActionProvider provider = actionItems.get(i).getActionProvider();
|
||||
if (provider != null) {
|
||||
provider.setSubUiVisibilityListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final ArrayList<MenuItemImpl> nonActionItems = mMenu != null ?
|
||||
mMenu.getNonActionItems() : null;
|
||||
|
||||
boolean hasOverflow = false;
|
||||
if (mReserveOverflow && nonActionItems != null) {
|
||||
final int count = nonActionItems.size();
|
||||
if (count == 1) {
|
||||
hasOverflow = !nonActionItems.get(0).isActionViewExpanded();
|
||||
} else {
|
||||
hasOverflow = count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasOverflow) {
|
||||
if (mOverflowButton == null) {
|
||||
mOverflowButton = new OverflowMenuButton(mSystemContext);
|
||||
}
|
||||
ViewGroup parent = (ViewGroup) mOverflowButton.getParent();
|
||||
if (parent != mMenuView) {
|
||||
if (parent != null) {
|
||||
parent.removeView(mOverflowButton);
|
||||
}
|
||||
ActionMenuView menuView = (ActionMenuView) mMenuView;
|
||||
menuView.addView(mOverflowButton, menuView.generateOverflowButtonLayoutParams());
|
||||
}
|
||||
} else if (mOverflowButton != null && mOverflowButton.getParent() == mMenuView) {
|
||||
((ViewGroup) mMenuView).removeView(mOverflowButton);
|
||||
}
|
||||
|
||||
((ActionMenuView) mMenuView).setOverflowReserved(mReserveOverflow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean filterLeftoverView(ViewGroup parent, int childIndex) {
|
||||
if (parent.getChildAt(childIndex) == mOverflowButton) return false;
|
||||
return super.filterLeftoverView(parent, childIndex);
|
||||
}
|
||||
|
||||
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
|
||||
if (!subMenu.hasVisibleItems()) return false;
|
||||
|
||||
SubMenuBuilder topSubMenu = subMenu;
|
||||
while (topSubMenu.getParentMenu() != mMenu) {
|
||||
topSubMenu = (SubMenuBuilder) topSubMenu.getParentMenu();
|
||||
}
|
||||
View anchor = findViewForItem(topSubMenu.getItem());
|
||||
if (anchor == null) {
|
||||
if (mOverflowButton == null) return false;
|
||||
anchor = mOverflowButton;
|
||||
}
|
||||
|
||||
mOpenSubMenuId = subMenu.getItem().getItemId();
|
||||
mActionButtonPopup = new ActionButtonSubmenu(mContext, subMenu);
|
||||
mActionButtonPopup.setAnchorView(anchor);
|
||||
mActionButtonPopup.show();
|
||||
super.onSubMenuSelected(subMenu);
|
||||
return true;
|
||||
}
|
||||
|
||||
private View findViewForItem(MenuItem item) {
|
||||
final ViewGroup parent = (ViewGroup) mMenuView;
|
||||
if (parent == null) return null;
|
||||
|
||||
final int count = parent.getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = parent.getChildAt(i);
|
||||
if (child instanceof MenuView.ItemView &&
|
||||
((MenuView.ItemView) child).getItemData() == item) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the overflow menu if one is present.
|
||||
* @return true if the overflow menu was shown, false otherwise.
|
||||
*/
|
||||
public boolean showOverflowMenu() {
|
||||
if (mReserveOverflow && !isOverflowMenuShowing() && mMenu != null && mMenuView != null &&
|
||||
mPostedOpenRunnable == null && !mMenu.getNonActionItems().isEmpty()) {
|
||||
OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true);
|
||||
mPostedOpenRunnable = new OpenOverflowRunnable(popup);
|
||||
// Post this for later; we might still need a layout for the anchor to be right.
|
||||
((View) mMenuView).post(mPostedOpenRunnable);
|
||||
|
||||
// ActionMenuPresenter uses null as a callback argument here
|
||||
// to indicate overflow is opening.
|
||||
super.onSubMenuSelected(null);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the overflow menu if it is currently showing.
|
||||
*
|
||||
* @return true if the overflow menu was hidden, false otherwise.
|
||||
*/
|
||||
public boolean hideOverflowMenu() {
|
||||
if (mPostedOpenRunnable != null && mMenuView != null) {
|
||||
((View) mMenuView).removeCallbacks(mPostedOpenRunnable);
|
||||
mPostedOpenRunnable = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
MenuPopupHelper popup = mOverflowPopup;
|
||||
if (popup != null) {
|
||||
popup.dismiss();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss all popup menus - overflow and submenus.
|
||||
* @return true if popups were dismissed, false otherwise. (This can be because none were open.)
|
||||
*/
|
||||
public boolean dismissPopupMenus() {
|
||||
boolean result = hideOverflowMenu();
|
||||
result |= hideSubMenus();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss all submenu popups.
|
||||
*
|
||||
* @return true if popups were dismissed, false otherwise. (This can be because none were open.)
|
||||
*/
|
||||
public boolean hideSubMenus() {
|
||||
if (mActionButtonPopup != null) {
|
||||
mActionButtonPopup.dismiss();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the overflow menu is currently showing
|
||||
*/
|
||||
public boolean isOverflowMenuShowing() {
|
||||
return mOverflowPopup != null && mOverflowPopup.isShowing();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if space has been reserved in the action menu for an overflow item.
|
||||
*/
|
||||
public boolean isOverflowReserved() {
|
||||
return mReserveOverflow;
|
||||
}
|
||||
|
||||
public boolean flagActionItems() {
|
||||
final ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
|
||||
final int itemsSize = visibleItems.size();
|
||||
int maxActions = mMaxItems;
|
||||
int widthLimit = mActionItemWidthLimit;
|
||||
final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
final ViewGroup parent = (ViewGroup) mMenuView;
|
||||
|
||||
int requiredItems = 0;
|
||||
int requestedItems = 0;
|
||||
int firstActionWidth = 0;
|
||||
boolean hasOverflow = false;
|
||||
for (int i = 0; i < itemsSize; i++) {
|
||||
MenuItemImpl item = visibleItems.get(i);
|
||||
if (item.requiresActionButton()) {
|
||||
requiredItems++;
|
||||
} else if (item.requestsActionButton()) {
|
||||
requestedItems++;
|
||||
} else {
|
||||
hasOverflow = true;
|
||||
}
|
||||
if (mExpandedActionViewsExclusive && item.isActionViewExpanded()) {
|
||||
// Overflow everything if we have an expanded action view and we're
|
||||
// space constrained.
|
||||
maxActions = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Reserve a spot for the overflow item if needed.
|
||||
if (mReserveOverflow &&
|
||||
(hasOverflow || requiredItems + requestedItems > maxActions)) {
|
||||
maxActions--;
|
||||
}
|
||||
maxActions -= requiredItems;
|
||||
|
||||
final SparseBooleanArray seenGroups = mActionButtonGroups;
|
||||
seenGroups.clear();
|
||||
|
||||
int cellSize = 0;
|
||||
int cellsRemaining = 0;
|
||||
if (mStrictWidthLimit) {
|
||||
cellsRemaining = widthLimit / mMinCellSize;
|
||||
final int cellSizeRemaining = widthLimit % mMinCellSize;
|
||||
cellSize = mMinCellSize + cellSizeRemaining / cellsRemaining;
|
||||
}
|
||||
|
||||
// Flag as many more requested items as will fit.
|
||||
for (int i = 0; i < itemsSize; i++) {
|
||||
MenuItemImpl item = visibleItems.get(i);
|
||||
|
||||
if (item.requiresActionButton()) {
|
||||
View v = getItemView(item, mScrapActionButtonView, parent);
|
||||
if (mScrapActionButtonView == null) {
|
||||
mScrapActionButtonView = v;
|
||||
}
|
||||
if (mStrictWidthLimit) {
|
||||
cellsRemaining -= ActionMenuView.measureChildForCells(v,
|
||||
cellSize, cellsRemaining, querySpec, 0);
|
||||
} else {
|
||||
v.measure(querySpec, querySpec);
|
||||
}
|
||||
final int measuredWidth = v.getMeasuredWidth();
|
||||
widthLimit -= measuredWidth;
|
||||
if (firstActionWidth == 0) {
|
||||
firstActionWidth = measuredWidth;
|
||||
}
|
||||
final int groupId = item.getGroupId();
|
||||
if (groupId != 0) {
|
||||
seenGroups.put(groupId, true);
|
||||
}
|
||||
item.setIsActionButton(true);
|
||||
} else if (item.requestsActionButton()) {
|
||||
// Items in a group with other items that already have an action slot
|
||||
// can break the max actions rule, but not the width limit.
|
||||
final int groupId = item.getGroupId();
|
||||
final boolean inGroup = seenGroups.get(groupId);
|
||||
boolean isAction = (maxActions > 0 || inGroup) && widthLimit > 0 &&
|
||||
(!mStrictWidthLimit || cellsRemaining > 0);
|
||||
|
||||
if (isAction) {
|
||||
View v = getItemView(item, mScrapActionButtonView, parent);
|
||||
if (mScrapActionButtonView == null) {
|
||||
mScrapActionButtonView = v;
|
||||
}
|
||||
if (mStrictWidthLimit) {
|
||||
final int cells = ActionMenuView.measureChildForCells(v,
|
||||
cellSize, cellsRemaining, querySpec, 0);
|
||||
cellsRemaining -= cells;
|
||||
if (cells == 0) {
|
||||
isAction = false;
|
||||
}
|
||||
} else {
|
||||
v.measure(querySpec, querySpec);
|
||||
}
|
||||
final int measuredWidth = v.getMeasuredWidth();
|
||||
widthLimit -= measuredWidth;
|
||||
if (firstActionWidth == 0) {
|
||||
firstActionWidth = measuredWidth;
|
||||
}
|
||||
|
||||
if (mStrictWidthLimit) {
|
||||
isAction &= widthLimit >= 0;
|
||||
} else {
|
||||
// Did this push the entire first item past the limit?
|
||||
isAction &= widthLimit + firstActionWidth > 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (isAction && groupId != 0) {
|
||||
seenGroups.put(groupId, true);
|
||||
} else if (inGroup) {
|
||||
// We broke the width limit. Demote the whole group, they all overflow now.
|
||||
seenGroups.put(groupId, false);
|
||||
for (int j = 0; j < i; j++) {
|
||||
MenuItemImpl areYouMyGroupie = visibleItems.get(j);
|
||||
if (areYouMyGroupie.getGroupId() == groupId) {
|
||||
// Give back the action slot
|
||||
if (areYouMyGroupie.isActionButton()) maxActions++;
|
||||
areYouMyGroupie.setIsActionButton(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isAction) maxActions--;
|
||||
|
||||
item.setIsActionButton(isAction);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||||
dismissPopupMenus();
|
||||
super.onCloseMenu(menu, allMenusAreClosing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
SavedState state = new SavedState();
|
||||
state.openSubMenuId = mOpenSubMenuId;
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
SavedState saved = (SavedState) state;
|
||||
if (saved.openSubMenuId > 0) {
|
||||
MenuItem item = mMenu.findItem(saved.openSubMenuId);
|
||||
if (item != null) {
|
||||
SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
|
||||
onSubMenuSelected(subMenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSubUiVisibilityChanged(boolean isVisible) {
|
||||
if (isVisible) {
|
||||
// Not a submenu, but treat it like one.
|
||||
super.onSubMenuSelected(null);
|
||||
} else {
|
||||
mMenu.close(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SavedState implements Parcelable {
|
||||
public int openSubMenuId;
|
||||
|
||||
SavedState() {
|
||||
}
|
||||
|
||||
SavedState(Parcel in) {
|
||||
openSubMenuId = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(openSubMenuId);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static final Parcelable.Creator<SavedState> CREATOR
|
||||
= new Parcelable.Creator<SavedState>() {
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private class OverflowMenuButton extends ImageButton implements ActionMenuChildView, View_HasStateListenerSupport {
|
||||
private final Set<View_OnAttachStateChangeListener> mListeners = new HashSet<View_OnAttachStateChangeListener>();
|
||||
|
||||
public OverflowMenuButton(Context context) {
|
||||
super(context, null, R.attr.actionOverflowButtonStyle);
|
||||
|
||||
setClickable(true);
|
||||
setFocusable(true);
|
||||
setVisibility(VISIBLE);
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performClick() {
|
||||
if (super.performClick()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
playSoundEffect(SoundEffectConstants.CLICK);
|
||||
showOverflowMenu();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean needsDividerBefore() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean needsDividerAfter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
for (View_OnAttachStateChangeListener listener : mListeners) {
|
||||
listener.onViewAttachedToWindow(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
for (View_OnAttachStateChangeListener listener : mListeners) {
|
||||
listener.onViewDetachedFromWindow(this);
|
||||
}
|
||||
|
||||
if (mOverflowPopup != null) mOverflowPopup.dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
private class OverflowPopup extends MenuPopupHelper {
|
||||
public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
|
||||
boolean overflowOnly) {
|
||||
super(context, menu, anchorView, overflowOnly);
|
||||
setCallback(mPopupPresenterCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss() {
|
||||
super.onDismiss();
|
||||
mMenu.close();
|
||||
mOverflowPopup = null;
|
||||
}
|
||||
}
|
||||
|
||||
private class ActionButtonSubmenu extends MenuPopupHelper {
|
||||
//UNUSED private SubMenuBuilder mSubMenu;
|
||||
|
||||
public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) {
|
||||
super(context, subMenu);
|
||||
//UNUSED mSubMenu = subMenu;
|
||||
|
||||
MenuItemImpl item = (MenuItemImpl) subMenu.getItem();
|
||||
if (!item.isActionButton()) {
|
||||
// Give a reasonable anchor to nested submenus.
|
||||
setAnchorView(mOverflowButton == null ? (View) mMenuView : mOverflowButton);
|
||||
}
|
||||
|
||||
setCallback(mPopupPresenterCallback);
|
||||
|
||||
boolean preserveIconSpacing = false;
|
||||
final int count = subMenu.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
MenuItem childItem = subMenu.getItem(i);
|
||||
if (childItem.isVisible() && childItem.getIcon() != null) {
|
||||
preserveIconSpacing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
setForceShowIcon(preserveIconSpacing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss() {
|
||||
super.onDismiss();
|
||||
mActionButtonPopup = null;
|
||||
mOpenSubMenuId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private class PopupPresenterCallback implements MenuPresenter.Callback {
|
||||
|
||||
@Override
|
||||
public boolean onOpenSubMenu(MenuBuilder subMenu) {
|
||||
if (subMenu == null) return false;
|
||||
|
||||
mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||||
if (menu instanceof SubMenuBuilder) {
|
||||
((SubMenuBuilder) menu).getRootMenu().close(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class OpenOverflowRunnable implements Runnable {
|
||||
private OverflowPopup mPopup;
|
||||
|
||||
public OpenOverflowRunnable(OverflowPopup popup) {
|
||||
mPopup = popup;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
mMenu.changeMenuMode();
|
||||
final View menuView = (View) mMenuView;
|
||||
if (menuView != null && menuView.getWindowToken() != null && mPopup.tryShow()) {
|
||||
mOverflowPopup = mPopup;
|
||||
}
|
||||
mPostedOpenRunnable = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,575 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Canvas;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.LinearLayout;
|
||||
import com.actionbarsherlock.internal.widget.IcsLinearLayout;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ActionMenuView extends IcsLinearLayout implements MenuBuilder.ItemInvoker, MenuView {
|
||||
//UNUSED private static final String TAG = "ActionMenuView";
|
||||
private static final boolean IS_FROYO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
|
||||
|
||||
static final int MIN_CELL_SIZE = 56; // dips
|
||||
static final int GENERATED_ITEM_PADDING = 4; // dips
|
||||
|
||||
private MenuBuilder mMenu;
|
||||
|
||||
private boolean mReserveOverflow;
|
||||
private ActionMenuPresenter mPresenter;
|
||||
private boolean mFormatItems;
|
||||
private int mFormatItemsWidth;
|
||||
private int mMinCellSize;
|
||||
private int mGeneratedItemPadding;
|
||||
//UNUSED private int mMeasuredExtraWidth;
|
||||
|
||||
private boolean mFirst = true;
|
||||
|
||||
public ActionMenuView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ActionMenuView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setBaselineAligned(false);
|
||||
final float density = context.getResources().getDisplayMetrics().density;
|
||||
mMinCellSize = (int) (MIN_CELL_SIZE * density);
|
||||
mGeneratedItemPadding = (int) (GENERATED_ITEM_PADDING * density);
|
||||
}
|
||||
|
||||
public void setPresenter(ActionMenuPresenter presenter) {
|
||||
mPresenter = presenter;
|
||||
}
|
||||
|
||||
public boolean isExpandedFormat() {
|
||||
return mFormatItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
if (IS_FROYO) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
}
|
||||
mPresenter.updateMenuView(false);
|
||||
|
||||
if (mPresenter != null && mPresenter.isOverflowMenuShowing()) {
|
||||
mPresenter.hideOverflowMenu();
|
||||
mPresenter.showOverflowMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
//Need to trigger a relayout since we may have been added extremely
|
||||
//late in the initial rendering (e.g., when contained in a ViewPager).
|
||||
//See: https://github.com/JakeWharton/ActionBarSherlock/issues/272
|
||||
if (!IS_FROYO && mFirst) {
|
||||
mFirst = false;
|
||||
requestLayout();
|
||||
return;
|
||||
}
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
// If we've been given an exact size to match, apply special formatting during layout.
|
||||
final boolean wasFormatted = mFormatItems;
|
||||
mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
|
||||
|
||||
if (wasFormatted != mFormatItems) {
|
||||
mFormatItemsWidth = 0; // Reset this when switching modes
|
||||
}
|
||||
|
||||
// Special formatting can change whether items can fit as action buttons.
|
||||
// Kick the menu and update presenters when this changes.
|
||||
final int widthSize = MeasureSpec.getMode(widthMeasureSpec);
|
||||
if (mFormatItems && mMenu != null && widthSize != mFormatItemsWidth) {
|
||||
mFormatItemsWidth = widthSize;
|
||||
mMenu.onItemsChanged(true);
|
||||
}
|
||||
|
||||
if (mFormatItems) {
|
||||
onMeasureExactFormat(widthMeasureSpec, heightMeasureSpec);
|
||||
} else {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
}
|
||||
|
||||
private void onMeasureExactFormat(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
// We already know the width mode is EXACTLY if we're here.
|
||||
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
|
||||
|
||||
final int widthPadding = getPaddingLeft() + getPaddingRight();
|
||||
final int heightPadding = getPaddingTop() + getPaddingBottom();
|
||||
|
||||
widthSize -= widthPadding;
|
||||
|
||||
// Divide the view into cells.
|
||||
final int cellCount = widthSize / mMinCellSize;
|
||||
final int cellSizeRemaining = widthSize % mMinCellSize;
|
||||
|
||||
if (cellCount == 0) {
|
||||
// Give up, nothing fits.
|
||||
setMeasuredDimension(widthSize, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
final int cellSize = mMinCellSize + cellSizeRemaining / cellCount;
|
||||
|
||||
int cellsRemaining = cellCount;
|
||||
int maxChildHeight = 0;
|
||||
int maxCellsUsed = 0;
|
||||
int expandableItemCount = 0;
|
||||
int visibleItemCount = 0;
|
||||
boolean hasOverflow = false;
|
||||
|
||||
// This is used as a bitfield to locate the smallest items present. Assumes childCount < 64.
|
||||
long smallestItemsAt = 0;
|
||||
|
||||
final int childCount = getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) continue;
|
||||
|
||||
final boolean isGeneratedItem = child instanceof ActionMenuItemView;
|
||||
visibleItemCount++;
|
||||
|
||||
if (isGeneratedItem) {
|
||||
// Reset padding for generated menu item views; it may change below
|
||||
// and views are recycled.
|
||||
child.setPadding(mGeneratedItemPadding, 0, mGeneratedItemPadding, 0);
|
||||
}
|
||||
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
lp.expanded = false;
|
||||
lp.extraPixels = 0;
|
||||
lp.cellsUsed = 0;
|
||||
lp.expandable = false;
|
||||
lp.leftMargin = 0;
|
||||
lp.rightMargin = 0;
|
||||
lp.preventEdgeOffset = isGeneratedItem && ((ActionMenuItemView) child).hasText();
|
||||
|
||||
// Overflow always gets 1 cell. No more, no less.
|
||||
final int cellsAvailable = lp.isOverflowButton ? 1 : cellsRemaining;
|
||||
|
||||
final int cellsUsed = measureChildForCells(child, cellSize, cellsAvailable,
|
||||
heightMeasureSpec, heightPadding);
|
||||
|
||||
maxCellsUsed = Math.max(maxCellsUsed, cellsUsed);
|
||||
if (lp.expandable) expandableItemCount++;
|
||||
if (lp.isOverflowButton) hasOverflow = true;
|
||||
|
||||
cellsRemaining -= cellsUsed;
|
||||
maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight());
|
||||
if (cellsUsed == 1) smallestItemsAt |= (1 << i);
|
||||
}
|
||||
|
||||
// When we have overflow and a single expanded (text) item, we want to try centering it
|
||||
// visually in the available space even though overflow consumes some of it.
|
||||
final boolean centerSingleExpandedItem = hasOverflow && visibleItemCount == 2;
|
||||
|
||||
// Divide space for remaining cells if we have items that can expand.
|
||||
// Try distributing whole leftover cells to smaller items first.
|
||||
|
||||
boolean needsExpansion = false;
|
||||
while (expandableItemCount > 0 && cellsRemaining > 0) {
|
||||
int minCells = Integer.MAX_VALUE;
|
||||
long minCellsAt = 0; // Bit locations are indices of relevant child views
|
||||
int minCellsItemCount = 0;
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
|
||||
// Don't try to expand items that shouldn't.
|
||||
if (!lp.expandable) continue;
|
||||
|
||||
// Mark indices of children that can receive an extra cell.
|
||||
if (lp.cellsUsed < minCells) {
|
||||
minCells = lp.cellsUsed;
|
||||
minCellsAt = 1 << i;
|
||||
minCellsItemCount = 1;
|
||||
} else if (lp.cellsUsed == minCells) {
|
||||
minCellsAt |= 1 << i;
|
||||
minCellsItemCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Items that get expanded will always be in the set of smallest items when we're done.
|
||||
smallestItemsAt |= minCellsAt;
|
||||
|
||||
if (minCellsItemCount > cellsRemaining) break; // Couldn't expand anything evenly. Stop.
|
||||
|
||||
// We have enough cells, all minimum size items will be incremented.
|
||||
minCells++;
|
||||
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
if ((minCellsAt & (1 << i)) == 0) {
|
||||
// If this item is already at our small item count, mark it for later.
|
||||
if (lp.cellsUsed == minCells) smallestItemsAt |= 1 << i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (centerSingleExpandedItem && lp.preventEdgeOffset && cellsRemaining == 1) {
|
||||
// Add padding to this item such that it centers.
|
||||
child.setPadding(mGeneratedItemPadding + cellSize, 0, mGeneratedItemPadding, 0);
|
||||
}
|
||||
lp.cellsUsed++;
|
||||
lp.expanded = true;
|
||||
cellsRemaining--;
|
||||
}
|
||||
|
||||
needsExpansion = true;
|
||||
}
|
||||
|
||||
// Divide any space left that wouldn't divide along cell boundaries
|
||||
// evenly among the smallest items
|
||||
|
||||
final boolean singleItem = !hasOverflow && visibleItemCount == 1;
|
||||
if (cellsRemaining > 0 && smallestItemsAt != 0 &&
|
||||
(cellsRemaining < visibleItemCount - 1 || singleItem || maxCellsUsed > 1)) {
|
||||
float expandCount = Long.bitCount(smallestItemsAt);
|
||||
|
||||
if (!singleItem) {
|
||||
// The items at the far edges may only expand by half in order to pin to either side.
|
||||
if ((smallestItemsAt & 1) != 0) {
|
||||
LayoutParams lp = (LayoutParams) getChildAt(0).getLayoutParams();
|
||||
if (!lp.preventEdgeOffset) expandCount -= 0.5f;
|
||||
}
|
||||
if ((smallestItemsAt & (1 << (childCount - 1))) != 0) {
|
||||
LayoutParams lp = ((LayoutParams) getChildAt(childCount - 1).getLayoutParams());
|
||||
if (!lp.preventEdgeOffset) expandCount -= 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
final int extraPixels = expandCount > 0 ?
|
||||
(int) (cellsRemaining * cellSize / expandCount) : 0;
|
||||
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
if ((smallestItemsAt & (1 << i)) == 0) continue;
|
||||
|
||||
final View child = getChildAt(i);
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
if (child instanceof ActionMenuItemView) {
|
||||
// If this is one of our views, expand and measure at the larger size.
|
||||
lp.extraPixels = extraPixels;
|
||||
lp.expanded = true;
|
||||
if (i == 0 && !lp.preventEdgeOffset) {
|
||||
// First item gets part of its new padding pushed out of sight.
|
||||
// The last item will get this implicitly from layout.
|
||||
lp.leftMargin = -extraPixels / 2;
|
||||
}
|
||||
needsExpansion = true;
|
||||
} else if (lp.isOverflowButton) {
|
||||
lp.extraPixels = extraPixels;
|
||||
lp.expanded = true;
|
||||
lp.rightMargin = -extraPixels / 2;
|
||||
needsExpansion = true;
|
||||
} else {
|
||||
// If we don't know what it is, give it some margins instead
|
||||
// and let it center within its space. We still want to pin
|
||||
// against the edges.
|
||||
if (i != 0) {
|
||||
lp.leftMargin = extraPixels / 2;
|
||||
}
|
||||
if (i != childCount - 1) {
|
||||
lp.rightMargin = extraPixels / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cellsRemaining = 0;
|
||||
}
|
||||
|
||||
// Remeasure any items that have had extra space allocated to them.
|
||||
if (needsExpansion) {
|
||||
int heightSpec = MeasureSpec.makeMeasureSpec(heightSize - heightPadding, heightMode);
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
|
||||
if (!lp.expanded) continue;
|
||||
|
||||
final int width = lp.cellsUsed * cellSize + lp.extraPixels;
|
||||
child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), heightSpec);
|
||||
}
|
||||
}
|
||||
|
||||
if (heightMode != MeasureSpec.EXACTLY) {
|
||||
heightSize = maxChildHeight;
|
||||
}
|
||||
|
||||
setMeasuredDimension(widthSize, heightSize);
|
||||
//UNUSED mMeasuredExtraWidth = cellsRemaining * cellSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Measure a child view to fit within cell-based formatting. The child's width
|
||||
* will be measured to a whole multiple of cellSize.
|
||||
*
|
||||
* <p>Sets the expandable and cellsUsed fields of LayoutParams.
|
||||
*
|
||||
* @param child Child to measure
|
||||
* @param cellSize Size of one cell
|
||||
* @param cellsRemaining Number of cells remaining that this view can expand to fill
|
||||
* @param parentHeightMeasureSpec MeasureSpec used by the parent view
|
||||
* @param parentHeightPadding Padding present in the parent view
|
||||
* @return Number of cells this child was measured to occupy
|
||||
*/
|
||||
static int measureChildForCells(View child, int cellSize, int cellsRemaining,
|
||||
int parentHeightMeasureSpec, int parentHeightPadding) {
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
|
||||
final int childHeightSize = MeasureSpec.getSize(parentHeightMeasureSpec) -
|
||||
parentHeightPadding;
|
||||
final int childHeightMode = MeasureSpec.getMode(parentHeightMeasureSpec);
|
||||
final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode);
|
||||
|
||||
int cellsUsed = 0;
|
||||
if (cellsRemaining > 0) {
|
||||
final int childWidthSpec = MeasureSpec.makeMeasureSpec(
|
||||
cellSize * cellsRemaining, MeasureSpec.AT_MOST);
|
||||
child.measure(childWidthSpec, childHeightSpec);
|
||||
|
||||
final int measuredWidth = child.getMeasuredWidth();
|
||||
cellsUsed = measuredWidth / cellSize;
|
||||
if (measuredWidth % cellSize != 0) cellsUsed++;
|
||||
}
|
||||
|
||||
final ActionMenuItemView itemView = child instanceof ActionMenuItemView ?
|
||||
(ActionMenuItemView) child : null;
|
||||
final boolean expandable = !lp.isOverflowButton && itemView != null && itemView.hasText();
|
||||
lp.expandable = expandable;
|
||||
|
||||
lp.cellsUsed = cellsUsed;
|
||||
final int targetWidth = cellsUsed * cellSize;
|
||||
child.measure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY),
|
||||
childHeightSpec);
|
||||
return cellsUsed;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
if (!mFormatItems) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
return;
|
||||
}
|
||||
|
||||
final int childCount = getChildCount();
|
||||
final int midVertical = (top + bottom) / 2;
|
||||
final int dividerWidth = 0;//getDividerWidth();
|
||||
int overflowWidth = 0;
|
||||
//UNUSED int nonOverflowWidth = 0;
|
||||
int nonOverflowCount = 0;
|
||||
int widthRemaining = right - left - getPaddingRight() - getPaddingLeft();
|
||||
boolean hasOverflow = false;
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View v = getChildAt(i);
|
||||
if (v.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LayoutParams p = (LayoutParams) v.getLayoutParams();
|
||||
if (p.isOverflowButton) {
|
||||
overflowWidth = v.getMeasuredWidth();
|
||||
if (hasDividerBeforeChildAt(i)) {
|
||||
overflowWidth += dividerWidth;
|
||||
}
|
||||
|
||||
int height = v.getMeasuredHeight();
|
||||
int r = getWidth() - getPaddingRight() - p.rightMargin;
|
||||
int l = r - overflowWidth;
|
||||
int t = midVertical - (height / 2);
|
||||
int b = t + height;
|
||||
v.layout(l, t, r, b);
|
||||
|
||||
widthRemaining -= overflowWidth;
|
||||
hasOverflow = true;
|
||||
} else {
|
||||
final int size = v.getMeasuredWidth() + p.leftMargin + p.rightMargin;
|
||||
//UNUSED nonOverflowWidth += size;
|
||||
widthRemaining -= size;
|
||||
//if (hasDividerBeforeChildAt(i)) {
|
||||
//UNUSED nonOverflowWidth += dividerWidth;
|
||||
//}
|
||||
nonOverflowCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (childCount == 1 && !hasOverflow) {
|
||||
// Center a single child
|
||||
final View v = getChildAt(0);
|
||||
final int width = v.getMeasuredWidth();
|
||||
final int height = v.getMeasuredHeight();
|
||||
final int midHorizontal = (right - left) / 2;
|
||||
final int l = midHorizontal - width / 2;
|
||||
final int t = midVertical - height / 2;
|
||||
v.layout(l, t, l + width, t + height);
|
||||
return;
|
||||
}
|
||||
|
||||
final int spacerCount = nonOverflowCount - (hasOverflow ? 0 : 1);
|
||||
final int spacerSize = Math.max(0, spacerCount > 0 ? widthRemaining / spacerCount : 0);
|
||||
|
||||
int startLeft = getPaddingLeft();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View v = getChildAt(i);
|
||||
final LayoutParams lp = (LayoutParams) v.getLayoutParams();
|
||||
if (v.getVisibility() == GONE || lp.isOverflowButton) {
|
||||
continue;
|
||||
}
|
||||
|
||||
startLeft += lp.leftMargin;
|
||||
int width = v.getMeasuredWidth();
|
||||
int height = v.getMeasuredHeight();
|
||||
int t = midVertical - height / 2;
|
||||
v.layout(startLeft, t, startLeft + width, t + height);
|
||||
startLeft += width + lp.rightMargin + spacerSize;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mPresenter.dismissPopupMenus();
|
||||
}
|
||||
|
||||
public boolean isOverflowReserved() {
|
||||
return mReserveOverflow;
|
||||
}
|
||||
|
||||
public void setOverflowReserved(boolean reserveOverflow) {
|
||||
mReserveOverflow = reserveOverflow;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LayoutParams generateDefaultLayoutParams() {
|
||||
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.WRAP_CONTENT);
|
||||
params.gravity = Gravity.CENTER_VERTICAL;
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutParams generateLayoutParams(AttributeSet attrs) {
|
||||
return new LayoutParams(getContext(), attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
|
||||
if (p instanceof LayoutParams) {
|
||||
LayoutParams result = new LayoutParams((LayoutParams) p);
|
||||
if (result.gravity <= Gravity.NO_GRAVITY) {
|
||||
result.gravity = Gravity.CENTER_VERTICAL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return generateDefaultLayoutParams();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
|
||||
return p != null && p instanceof LayoutParams;
|
||||
}
|
||||
|
||||
public LayoutParams generateOverflowButtonLayoutParams() {
|
||||
LayoutParams result = generateDefaultLayoutParams();
|
||||
result.isOverflowButton = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean invokeItem(MenuItemImpl item) {
|
||||
return mMenu.performItemAction(item, 0);
|
||||
}
|
||||
|
||||
public int getWindowAnimations() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void initialize(MenuBuilder menu) {
|
||||
mMenu = menu;
|
||||
}
|
||||
|
||||
//@Override
|
||||
protected boolean hasDividerBeforeChildAt(int childIndex) {
|
||||
if (childIndex == 0) {
|
||||
return false;
|
||||
}
|
||||
final View childBefore = getChildAt(childIndex - 1);
|
||||
final View child = getChildAt(childIndex);
|
||||
boolean result = false;
|
||||
if (childIndex < getChildCount() && childBefore instanceof ActionMenuChildView) {
|
||||
result |= ((ActionMenuChildView) childBefore).needsDividerAfter();
|
||||
}
|
||||
if (childIndex > 0 && child instanceof ActionMenuChildView) {
|
||||
result |= ((ActionMenuChildView) child).needsDividerBefore();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public interface ActionMenuChildView {
|
||||
public boolean needsDividerBefore();
|
||||
public boolean needsDividerAfter();
|
||||
}
|
||||
|
||||
public static class LayoutParams extends LinearLayout.LayoutParams {
|
||||
public boolean isOverflowButton;
|
||||
public int cellsUsed;
|
||||
public int extraPixels;
|
||||
public boolean expandable;
|
||||
public boolean preventEdgeOffset;
|
||||
|
||||
public boolean expanded;
|
||||
|
||||
public LayoutParams(Context c, AttributeSet attrs) {
|
||||
super(c, attrs);
|
||||
}
|
||||
|
||||
public LayoutParams(LayoutParams other) {
|
||||
super((LinearLayout.LayoutParams) other);
|
||||
isOverflowButton = other.isOverflowButton;
|
||||
}
|
||||
|
||||
public LayoutParams(int width, int height) {
|
||||
super(width, height);
|
||||
isOverflowButton = false;
|
||||
}
|
||||
|
||||
public LayoutParams(int width, int height, boolean isOverflowButton) {
|
||||
super(width, height);
|
||||
this.isOverflowButton = isOverflowButton;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,231 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 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.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* Base class for MenuPresenters that have a consistent container view and item
|
||||
* views. Behaves similarly to an AdapterView in that existing item views will
|
||||
* be reused if possible when items change.
|
||||
*/
|
||||
public abstract class BaseMenuPresenter implements MenuPresenter {
|
||||
private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
|
||||
|
||||
protected Context mSystemContext;
|
||||
protected Context mContext;
|
||||
protected MenuBuilder mMenu;
|
||||
protected LayoutInflater mSystemInflater;
|
||||
protected LayoutInflater mInflater;
|
||||
private Callback mCallback;
|
||||
|
||||
private int mMenuLayoutRes;
|
||||
private int mItemLayoutRes;
|
||||
|
||||
protected MenuView mMenuView;
|
||||
|
||||
private int mId;
|
||||
|
||||
/**
|
||||
* Construct a new BaseMenuPresenter.
|
||||
*
|
||||
* @param context Context for generating system-supplied views
|
||||
* @param menuLayoutRes Layout resource ID for the menu container view
|
||||
* @param itemLayoutRes Layout resource ID for a single item view
|
||||
*/
|
||||
public BaseMenuPresenter(Context context, int menuLayoutRes, int itemLayoutRes) {
|
||||
mSystemContext = context;
|
||||
mSystemInflater = LayoutInflater.from(context);
|
||||
mMenuLayoutRes = menuLayoutRes;
|
||||
mItemLayoutRes = itemLayoutRes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initForMenu(Context context, MenuBuilder menu) {
|
||||
mContext = context;
|
||||
mInflater = LayoutInflater.from(mContext);
|
||||
mMenu = menu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuView getMenuView(ViewGroup root) {
|
||||
if (mMenuView == null) {
|
||||
mMenuView = (MenuView) mSystemInflater.inflate(mMenuLayoutRes, root, false);
|
||||
mMenuView.initialize(mMenu);
|
||||
updateMenuView(true);
|
||||
}
|
||||
|
||||
return mMenuView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reuses item views when it can
|
||||
*/
|
||||
public void updateMenuView(boolean cleared) {
|
||||
final ViewGroup parent = (ViewGroup) mMenuView;
|
||||
if (parent == null) return;
|
||||
|
||||
int childIndex = 0;
|
||||
if (mMenu != null) {
|
||||
mMenu.flagActionItems();
|
||||
ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
|
||||
final int itemCount = visibleItems.size();
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
MenuItemImpl item = visibleItems.get(i);
|
||||
if (shouldIncludeItem(childIndex, item)) {
|
||||
final View convertView = parent.getChildAt(childIndex);
|
||||
final MenuItemImpl oldItem = convertView instanceof MenuView.ItemView ?
|
||||
((MenuView.ItemView) convertView).getItemData() : null;
|
||||
final View itemView = getItemView(item, convertView, parent);
|
||||
if (item != oldItem) {
|
||||
// Don't let old states linger with new data.
|
||||
itemView.setPressed(false);
|
||||
if (IS_HONEYCOMB) itemView.jumpDrawablesToCurrentState();
|
||||
}
|
||||
if (itemView != convertView) {
|
||||
addItemView(itemView, childIndex);
|
||||
}
|
||||
childIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove leftover views.
|
||||
while (childIndex < parent.getChildCount()) {
|
||||
if (!filterLeftoverView(parent, childIndex)) {
|
||||
childIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item view at the given index.
|
||||
*
|
||||
* @param itemView View to add
|
||||
* @param childIndex Index within the parent to insert at
|
||||
*/
|
||||
protected void addItemView(View itemView, int childIndex) {
|
||||
final ViewGroup currentParent = (ViewGroup) itemView.getParent();
|
||||
if (currentParent != null) {
|
||||
currentParent.removeView(itemView);
|
||||
}
|
||||
((ViewGroup) mMenuView).addView(itemView, childIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the child view at index and remove it if appropriate.
|
||||
* @param parent Parent to filter from
|
||||
* @param childIndex Index to filter
|
||||
* @return true if the child view at index was removed
|
||||
*/
|
||||
protected boolean filterLeftoverView(ViewGroup parent, int childIndex) {
|
||||
parent.removeViewAt(childIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setCallback(Callback cb) {
|
||||
mCallback = cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new item view that can be re-bound to other item data later.
|
||||
*
|
||||
* @return The new item view
|
||||
*/
|
||||
public MenuView.ItemView createItemView(ViewGroup parent) {
|
||||
return (MenuView.ItemView) mSystemInflater.inflate(mItemLayoutRes, parent, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an item view for use. See AdapterView for the basic idea at work here.
|
||||
* This may require creating a new item view, but well-behaved implementations will
|
||||
* re-use the view passed as convertView if present. The returned view will be populated
|
||||
* with data from the item parameter.
|
||||
*
|
||||
* @param item Item to present
|
||||
* @param convertView Existing view to reuse
|
||||
* @param parent Intended parent view - use for inflation.
|
||||
* @return View that presents the requested menu item
|
||||
*/
|
||||
public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
|
||||
MenuView.ItemView itemView;
|
||||
if (convertView instanceof MenuView.ItemView) {
|
||||
itemView = (MenuView.ItemView) convertView;
|
||||
} else {
|
||||
itemView = createItemView(parent);
|
||||
}
|
||||
bindItemView(item, itemView);
|
||||
return (View) itemView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind item data to an existing item view.
|
||||
*
|
||||
* @param item Item to bind
|
||||
* @param itemView View to populate with item data
|
||||
*/
|
||||
public abstract void bindItemView(MenuItemImpl item, MenuView.ItemView itemView);
|
||||
|
||||
/**
|
||||
* Filter item by child index and item data.
|
||||
*
|
||||
* @param childIndex Indended presentation index of this item
|
||||
* @param item Item to present
|
||||
* @return true if this item should be included in this menu presentation; false otherwise
|
||||
*/
|
||||
public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||||
if (mCallback != null) {
|
||||
mCallback.onCloseMenu(menu, allMenusAreClosing);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onSubMenuSelected(SubMenuBuilder menu) {
|
||||
if (mCallback != null) {
|
||||
return mCallback.onOpenSubMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean flagActionItems() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
mId = id;
|
||||
}
|
||||
}
|
@ -1,278 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* The item view for each item in the ListView-based MenuViews.
|
||||
*/
|
||||
public class ListMenuItemView extends LinearLayout implements MenuView.ItemView {
|
||||
private MenuItemImpl mItemData;
|
||||
|
||||
private ImageView mIconView;
|
||||
private RadioButton mRadioButton;
|
||||
private TextView mTitleView;
|
||||
private CheckBox mCheckBox;
|
||||
private TextView mShortcutView;
|
||||
|
||||
private Drawable mBackground;
|
||||
private int mTextAppearance;
|
||||
private Context mTextAppearanceContext;
|
||||
private boolean mPreserveIconSpacing;
|
||||
|
||||
//UNUSED private int mMenuType;
|
||||
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
private boolean mForceShowIcon;
|
||||
|
||||
final Context mContext;
|
||||
|
||||
public ListMenuItemView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
|
||||
TypedArray a =
|
||||
context.obtainStyledAttributes(
|
||||
attrs, R.styleable.SherlockMenuView, defStyle, 0);
|
||||
|
||||
mBackground = a.getDrawable(R.styleable.SherlockMenuView_itemBackground);
|
||||
mTextAppearance = a.getResourceId(R.styleable.
|
||||
SherlockMenuView_itemTextAppearance, -1);
|
||||
mPreserveIconSpacing = a.getBoolean(
|
||||
R.styleable.SherlockMenuView_preserveIconSpacing, false);
|
||||
mTextAppearanceContext = context;
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public ListMenuItemView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
setBackgroundDrawable(mBackground);
|
||||
|
||||
mTitleView = (TextView) findViewById(R.id.abs__title);
|
||||
if (mTextAppearance != -1) {
|
||||
mTitleView.setTextAppearance(mTextAppearanceContext,
|
||||
mTextAppearance);
|
||||
}
|
||||
|
||||
mShortcutView = (TextView) findViewById(R.id.abs__shortcut);
|
||||
}
|
||||
|
||||
public void initialize(MenuItemImpl itemData, int menuType) {
|
||||
mItemData = itemData;
|
||||
//UNUSED mMenuType = menuType;
|
||||
|
||||
setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
|
||||
|
||||
setTitle(itemData.getTitleForItemView(this));
|
||||
setCheckable(itemData.isCheckable());
|
||||
setShortcut(itemData.shouldShowShortcut(), itemData.getShortcut());
|
||||
setIcon(itemData.getIcon());
|
||||
setEnabled(itemData.isEnabled());
|
||||
}
|
||||
|
||||
public void setForceShowIcon(boolean forceShow) {
|
||||
mPreserveIconSpacing = mForceShowIcon = forceShow;
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence title) {
|
||||
if (title != null) {
|
||||
mTitleView.setText(title);
|
||||
|
||||
if (mTitleView.getVisibility() != VISIBLE) mTitleView.setVisibility(VISIBLE);
|
||||
} else {
|
||||
if (mTitleView.getVisibility() != GONE) mTitleView.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public MenuItemImpl getItemData() {
|
||||
return mItemData;
|
||||
}
|
||||
|
||||
public void setCheckable(boolean checkable) {
|
||||
|
||||
if (!checkable && mRadioButton == null && mCheckBox == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRadioButton == null) {
|
||||
insertRadioButton();
|
||||
}
|
||||
if (mCheckBox == null) {
|
||||
insertCheckBox();
|
||||
}
|
||||
|
||||
// Depending on whether its exclusive check or not, the checkbox or
|
||||
// radio button will be the one in use (and the other will be otherCompoundButton)
|
||||
final CompoundButton compoundButton;
|
||||
final CompoundButton otherCompoundButton;
|
||||
|
||||
if (mItemData.isExclusiveCheckable()) {
|
||||
compoundButton = mRadioButton;
|
||||
otherCompoundButton = mCheckBox;
|
||||
} else {
|
||||
compoundButton = mCheckBox;
|
||||
otherCompoundButton = mRadioButton;
|
||||
}
|
||||
|
||||
if (checkable) {
|
||||
compoundButton.setChecked(mItemData.isChecked());
|
||||
|
||||
final int newVisibility = checkable ? VISIBLE : GONE;
|
||||
if (compoundButton.getVisibility() != newVisibility) {
|
||||
compoundButton.setVisibility(newVisibility);
|
||||
}
|
||||
|
||||
// Make sure the other compound button isn't visible
|
||||
if (otherCompoundButton.getVisibility() != GONE) {
|
||||
otherCompoundButton.setVisibility(GONE);
|
||||
}
|
||||
} else {
|
||||
mCheckBox.setVisibility(GONE);
|
||||
mRadioButton.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
CompoundButton compoundButton;
|
||||
|
||||
if (mItemData.isExclusiveCheckable()) {
|
||||
if (mRadioButton == null) {
|
||||
insertRadioButton();
|
||||
}
|
||||
compoundButton = mRadioButton;
|
||||
} else {
|
||||
if (mCheckBox == null) {
|
||||
insertCheckBox();
|
||||
}
|
||||
compoundButton = mCheckBox;
|
||||
}
|
||||
|
||||
compoundButton.setChecked(checked);
|
||||
}
|
||||
|
||||
public void setShortcut(boolean showShortcut, char shortcutKey) {
|
||||
final int newVisibility = (showShortcut && mItemData.shouldShowShortcut())
|
||||
? VISIBLE : GONE;
|
||||
|
||||
if (newVisibility == VISIBLE) {
|
||||
mShortcutView.setText(mItemData.getShortcutLabel());
|
||||
}
|
||||
|
||||
if (mShortcutView.getVisibility() != newVisibility) {
|
||||
mShortcutView.setVisibility(newVisibility);
|
||||
}
|
||||
}
|
||||
|
||||
public void setIcon(Drawable icon) {
|
||||
final boolean showIcon = mItemData.shouldShowIcon() || mForceShowIcon;
|
||||
if (!showIcon && !mPreserveIconSpacing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIconView == null && icon == null && !mPreserveIconSpacing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIconView == null) {
|
||||
insertIconView();
|
||||
}
|
||||
|
||||
if (icon != null || mPreserveIconSpacing) {
|
||||
mIconView.setImageDrawable(showIcon ? icon : null);
|
||||
|
||||
if (mIconView.getVisibility() != VISIBLE) {
|
||||
mIconView.setVisibility(VISIBLE);
|
||||
}
|
||||
} else {
|
||||
mIconView.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
if (mIconView != null && mPreserveIconSpacing) {
|
||||
// Enforce minimum icon spacing
|
||||
ViewGroup.LayoutParams lp = getLayoutParams();
|
||||
LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
|
||||
if (lp.height > 0 && iconLp.width <= 0) {
|
||||
iconLp.width = lp.height;
|
||||
}
|
||||
}
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
private void insertIconView() {
|
||||
LayoutInflater inflater = getInflater();
|
||||
mIconView = (ImageView) inflater.inflate(R.layout.abs__list_menu_item_icon,
|
||||
this, false);
|
||||
addView(mIconView, 0);
|
||||
}
|
||||
|
||||
private void insertRadioButton() {
|
||||
LayoutInflater inflater = getInflater();
|
||||
mRadioButton =
|
||||
(RadioButton) inflater.inflate(R.layout.abs__list_menu_item_radio,
|
||||
this, false);
|
||||
addView(mRadioButton);
|
||||
}
|
||||
|
||||
private void insertCheckBox() {
|
||||
LayoutInflater inflater = getInflater();
|
||||
mCheckBox =
|
||||
(CheckBox) inflater.inflate(R.layout.abs__list_menu_item_checkbox,
|
||||
this, false);
|
||||
addView(mCheckBox);
|
||||
}
|
||||
|
||||
public boolean prefersCondensedTitle() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean showsIcon() {
|
||||
return mForceShowIcon;
|
||||
}
|
||||
|
||||
private LayoutInflater getInflater() {
|
||||
if (mInflater == null) {
|
||||
mInflater = LayoutInflater.from(mContext);
|
||||
}
|
||||
return mInflater;
|
||||
}
|
||||
}
|
@ -1,647 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public final class MenuItemImpl implements MenuItem {
|
||||
private static final String TAG = "MenuItemImpl";
|
||||
|
||||
private static final int SHOW_AS_ACTION_MASK = SHOW_AS_ACTION_NEVER |
|
||||
SHOW_AS_ACTION_IF_ROOM |
|
||||
SHOW_AS_ACTION_ALWAYS;
|
||||
|
||||
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;
|
||||
|
||||
/** The icon's drawable which is only created as needed */
|
||||
private Drawable mIconDrawable;
|
||||
/**
|
||||
* The icon's resource ID which is used to get the Drawable when it is
|
||||
* needed (if the Drawable isn't already obtained--only one of the two is
|
||||
* needed).
|
||||
*/
|
||||
private int mIconResId = NO_ICON;
|
||||
|
||||
/** The menu to which this item belongs */
|
||||
private MenuBuilder mMenu;
|
||||
/** If this item should launch a sub menu, this is the sub menu to launch */
|
||||
private SubMenuBuilder mSubMenu;
|
||||
|
||||
private Runnable mItemCallback;
|
||||
private MenuItem.OnMenuItemClickListener mClickListener;
|
||||
|
||||
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;
|
||||
private static final int IS_ACTION = 0x00000020;
|
||||
|
||||
private int mShowAsAction = SHOW_AS_ACTION_NEVER;
|
||||
|
||||
private View mActionView;
|
||||
private ActionProvider mActionProvider;
|
||||
private OnActionExpandListener mOnActionExpandListener;
|
||||
private boolean mIsActionViewExpanded = false;
|
||||
|
||||
/** Used for the icon resource ID if this item does not have an icon */
|
||||
static final int NO_ICON = 0;
|
||||
|
||||
/**
|
||||
* Current use case is for context menu: Extra information linked to the
|
||||
* View that added this item to the context menu.
|
||||
*/
|
||||
private ContextMenuInfo mMenuInfo;
|
||||
|
||||
private static String sPrependShortcutLabel;
|
||||
private static String sEnterShortcutLabel;
|
||||
private static String sDeleteShortcutLabel;
|
||||
private static String sSpaceShortcutLabel;
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates this menu item.
|
||||
*
|
||||
* @param menu
|
||||
* @param group Item ordering grouping control. The item will be added after
|
||||
* all other items whose order is <= this number, and before any
|
||||
* that are larger than it. This can also be used to define
|
||||
* groups of items for batch state changes. Normally use 0.
|
||||
* @param id Unique item ID. Use 0 if you do not need a unique ID.
|
||||
* @param categoryOrder The ordering for this item.
|
||||
* @param title The text to display for the item.
|
||||
*/
|
||||
MenuItemImpl(MenuBuilder menu, int group, int id, int categoryOrder, int ordering,
|
||||
CharSequence title, int showAsAction) {
|
||||
|
||||
/* TODO if (sPrependShortcutLabel == null) {
|
||||
// This is instantiated from the UI thread, so no chance of sync issues
|
||||
sPrependShortcutLabel = menu.getContext().getResources().getString(
|
||||
com.android.internal.R.string.prepend_shortcut_label);
|
||||
sEnterShortcutLabel = menu.getContext().getResources().getString(
|
||||
com.android.internal.R.string.menu_enter_shortcut_label);
|
||||
sDeleteShortcutLabel = menu.getContext().getResources().getString(
|
||||
com.android.internal.R.string.menu_delete_shortcut_label);
|
||||
sSpaceShortcutLabel = menu.getContext().getResources().getString(
|
||||
com.android.internal.R.string.menu_space_shortcut_label);
|
||||
}*/
|
||||
|
||||
mMenu = menu;
|
||||
mId = id;
|
||||
mGroup = group;
|
||||
mCategoryOrder = categoryOrder;
|
||||
mOrdering = ordering;
|
||||
mTitle = title;
|
||||
mShowAsAction = showAsAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the item by calling various listeners or callbacks.
|
||||
*
|
||||
* @return true if the invocation was handled, false otherwise
|
||||
*/
|
||||
public boolean invoke() {
|
||||
if (mClickListener != null &&
|
||||
mClickListener.onMenuItemClick(this)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mMenu.dispatchMenuItemSelected(mMenu.getRootMenu(), this)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mItemCallback != null) {
|
||||
mItemCallback.run();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mIntent != null) {
|
||||
try {
|
||||
mMenu.getContext().startActivity(mIntent);
|
||||
return true;
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Log.e(TAG, "Can't find activity to handle intent; ignoring", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (mActionProvider != null && mActionProvider.onPerformDefaultAction()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return (mFlags & ENABLED) != 0;
|
||||
}
|
||||
|
||||
public MenuItem setEnabled(boolean enabled) {
|
||||
if (enabled) {
|
||||
mFlags |= ENABLED;
|
||||
} else {
|
||||
mFlags &= ~ENABLED;
|
||||
}
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getGroupId() {
|
||||
return mGroup;
|
||||
}
|
||||
|
||||
@ViewDebug.CapturedViewProperty
|
||||
public int getItemId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return mCategoryOrder;
|
||||
}
|
||||
|
||||
public int getOrdering() {
|
||||
return mOrdering;
|
||||
}
|
||||
|
||||
public Intent getIntent() {
|
||||
return mIntent;
|
||||
}
|
||||
|
||||
public MenuItem setIntent(Intent intent) {
|
||||
mIntent = intent;
|
||||
return this;
|
||||
}
|
||||
|
||||
Runnable getCallback() {
|
||||
return mItemCallback;
|
||||
}
|
||||
|
||||
public MenuItem setCallback(Runnable callback) {
|
||||
mItemCallback = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public char getAlphabeticShortcut() {
|
||||
return mShortcutAlphabeticChar;
|
||||
}
|
||||
|
||||
public MenuItem setAlphabeticShortcut(char alphaChar) {
|
||||
if (mShortcutAlphabeticChar == alphaChar) return this;
|
||||
|
||||
mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public char getNumericShortcut() {
|
||||
return mShortcutNumericChar;
|
||||
}
|
||||
|
||||
public MenuItem setNumericShortcut(char numericChar) {
|
||||
if (mShortcutNumericChar == numericChar) return this;
|
||||
|
||||
mShortcutNumericChar = numericChar;
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setShortcut(char numericChar, char alphaChar) {
|
||||
mShortcutNumericChar = numericChar;
|
||||
mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The active shortcut (based on QWERTY-mode of the menu).
|
||||
*/
|
||||
char getShortcut() {
|
||||
return (mMenu.isQwertyMode() ? mShortcutAlphabeticChar : mShortcutNumericChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The label to show for the shortcut. This includes the chording
|
||||
* key (for example 'Menu+a'). Also, any non-human readable
|
||||
* characters should be human readable (for example 'Menu+enter').
|
||||
*/
|
||||
String getShortcutLabel() {
|
||||
|
||||
char shortcut = getShortcut();
|
||||
if (shortcut == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(sPrependShortcutLabel);
|
||||
switch (shortcut) {
|
||||
|
||||
case '\n':
|
||||
sb.append(sEnterShortcutLabel);
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
sb.append(sDeleteShortcutLabel);
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
sb.append(sSpaceShortcutLabel);
|
||||
break;
|
||||
|
||||
default:
|
||||
sb.append(shortcut);
|
||||
break;
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether this menu item should be showing shortcuts (depends on
|
||||
* whether the menu should show shortcuts and whether this item has
|
||||
* a shortcut defined)
|
||||
*/
|
||||
boolean shouldShowShortcut() {
|
||||
// Show shortcuts if the menu is supposed to show shortcuts AND this item has a shortcut
|
||||
return mMenu.isShortcutsVisible() && (getShortcut() != 0);
|
||||
}
|
||||
|
||||
public SubMenu getSubMenu() {
|
||||
return mSubMenu;
|
||||
}
|
||||
|
||||
public boolean hasSubMenu() {
|
||||
return mSubMenu != null;
|
||||
}
|
||||
|
||||
void setSubMenu(SubMenuBuilder subMenu) {
|
||||
mSubMenu = subMenu;
|
||||
|
||||
subMenu.setHeaderTitle(getTitle());
|
||||
}
|
||||
|
||||
@ViewDebug.CapturedViewProperty
|
||||
public CharSequence getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the title for a particular {@link ItemView}
|
||||
*
|
||||
* @param itemView The ItemView that is receiving the title
|
||||
* @return Either the title or condensed title based on what the ItemView
|
||||
* prefers
|
||||
*/
|
||||
CharSequence getTitleForItemView(MenuView.ItemView itemView) {
|
||||
return ((itemView != null) && itemView.prefersCondensedTitle())
|
||||
? getTitleCondensed()
|
||||
: getTitle();
|
||||
}
|
||||
|
||||
public MenuItem setTitle(CharSequence title) {
|
||||
mTitle = title;
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
if (mSubMenu != null) {
|
||||
mSubMenu.setHeaderTitle(title);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setTitle(int title) {
|
||||
return setTitle(mMenu.getContext().getString(title));
|
||||
}
|
||||
|
||||
public CharSequence getTitleCondensed() {
|
||||
return mTitleCondensed != null ? mTitleCondensed : mTitle;
|
||||
}
|
||||
|
||||
public MenuItem setTitleCondensed(CharSequence title) {
|
||||
mTitleCondensed = title;
|
||||
|
||||
// Could use getTitle() in the loop below, but just cache what it would do here
|
||||
if (title == null) {
|
||||
title = mTitle;
|
||||
}
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Drawable getIcon() {
|
||||
if (mIconDrawable != null) {
|
||||
return mIconDrawable;
|
||||
}
|
||||
|
||||
if (mIconResId != NO_ICON) {
|
||||
return mMenu.getResources().getDrawable(mIconResId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public MenuItem setIcon(Drawable icon) {
|
||||
mIconResId = NO_ICON;
|
||||
mIconDrawable = icon;
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setIcon(int iconResId) {
|
||||
mIconDrawable = null;
|
||||
mIconResId = iconResId;
|
||||
|
||||
// If we have a view, we need to push the Drawable to them
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isCheckable() {
|
||||
return (mFlags & CHECKABLE) == CHECKABLE;
|
||||
}
|
||||
|
||||
public MenuItem setCheckable(boolean checkable) {
|
||||
final int oldFlags = mFlags;
|
||||
mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0);
|
||||
if (oldFlags != mFlags) {
|
||||
mMenu.onItemsChanged(false);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setExclusiveCheckable(boolean exclusive) {
|
||||
mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0);
|
||||
}
|
||||
|
||||
public boolean isExclusiveCheckable() {
|
||||
return (mFlags & EXCLUSIVE) != 0;
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return (mFlags & CHECKED) == CHECKED;
|
||||
}
|
||||
|
||||
public MenuItem setChecked(boolean checked) {
|
||||
if ((mFlags & EXCLUSIVE) != 0) {
|
||||
// Call the method on the Menu since it knows about the others in this
|
||||
// exclusive checkable group
|
||||
mMenu.setExclusiveItemChecked(this);
|
||||
} else {
|
||||
setCheckedInt(checked);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void setCheckedInt(boolean checked) {
|
||||
final int oldFlags = mFlags;
|
||||
mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0);
|
||||
if (oldFlags != mFlags) {
|
||||
mMenu.onItemsChanged(false);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return (mFlags & HIDDEN) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the visibility of the item. This method DOES NOT notify the
|
||||
* parent menu of a change in this item, so this should only be called from
|
||||
* methods that will eventually trigger this change. If unsure, use {@link #setVisible(boolean)}
|
||||
* instead.
|
||||
*
|
||||
* @param shown Whether to show (true) or hide (false).
|
||||
* @return Whether the item's shown state was changed
|
||||
*/
|
||||
boolean setVisibleInt(boolean shown) {
|
||||
final int oldFlags = mFlags;
|
||||
mFlags = (mFlags & ~HIDDEN) | (shown ? 0 : HIDDEN);
|
||||
return oldFlags != mFlags;
|
||||
}
|
||||
|
||||
public MenuItem setVisible(boolean shown) {
|
||||
// Try to set the shown state to the given state. If the shown state was changed
|
||||
// (i.e. the previous state isn't the same as given state), notify the parent menu that
|
||||
// the shown state has changed for this item
|
||||
if (setVisibleInt(shown)) mMenu.onItemVisibleChanged(this);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener clickListener) {
|
||||
mClickListener = clickListener;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mTitle.toString();
|
||||
}
|
||||
|
||||
void setMenuInfo(ContextMenuInfo menuInfo) {
|
||||
mMenuInfo = menuInfo;
|
||||
}
|
||||
|
||||
public ContextMenuInfo getMenuInfo() {
|
||||
return mMenuInfo;
|
||||
}
|
||||
|
||||
public void actionFormatChanged() {
|
||||
mMenu.onItemActionRequestChanged(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the menu should show icons for menu items.
|
||||
*/
|
||||
public boolean shouldShowIcon() {
|
||||
return mMenu.getOptionalIconsVisible();
|
||||
}
|
||||
|
||||
public boolean isActionButton() {
|
||||
return (mFlags & IS_ACTION) == IS_ACTION;
|
||||
}
|
||||
|
||||
public boolean requestsActionButton() {
|
||||
return (mShowAsAction & SHOW_AS_ACTION_IF_ROOM) == SHOW_AS_ACTION_IF_ROOM;
|
||||
}
|
||||
|
||||
public boolean requiresActionButton() {
|
||||
return (mShowAsAction & SHOW_AS_ACTION_ALWAYS) == SHOW_AS_ACTION_ALWAYS;
|
||||
}
|
||||
|
||||
public void setIsActionButton(boolean isActionButton) {
|
||||
if (isActionButton) {
|
||||
mFlags |= IS_ACTION;
|
||||
} else {
|
||||
mFlags &= ~IS_ACTION;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean showsTextAsAction() {
|
||||
return (mShowAsAction & SHOW_AS_ACTION_WITH_TEXT) == SHOW_AS_ACTION_WITH_TEXT;
|
||||
}
|
||||
|
||||
public void setShowAsAction(int actionEnum) {
|
||||
switch (actionEnum & SHOW_AS_ACTION_MASK) {
|
||||
case SHOW_AS_ACTION_ALWAYS:
|
||||
case SHOW_AS_ACTION_IF_ROOM:
|
||||
case SHOW_AS_ACTION_NEVER:
|
||||
// Looks good!
|
||||
break;
|
||||
|
||||
default:
|
||||
// Mutually exclusive options selected!
|
||||
throw new IllegalArgumentException("SHOW_AS_ACTION_ALWAYS, SHOW_AS_ACTION_IF_ROOM,"
|
||||
+ " and SHOW_AS_ACTION_NEVER are mutually exclusive.");
|
||||
}
|
||||
mShowAsAction = actionEnum;
|
||||
mMenu.onItemActionRequestChanged(this);
|
||||
}
|
||||
|
||||
public MenuItem setActionView(View view) {
|
||||
mActionView = view;
|
||||
mActionProvider = null;
|
||||
if (view != null && view.getId() == View.NO_ID && mId > 0) {
|
||||
view.setId(mId);
|
||||
}
|
||||
mMenu.onItemActionRequestChanged(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setActionView(int resId) {
|
||||
final Context context = mMenu.getContext();
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
setActionView(inflater.inflate(resId, new LinearLayout(context), false));
|
||||
return this;
|
||||
}
|
||||
|
||||
public View getActionView() {
|
||||
if (mActionView != null) {
|
||||
return mActionView;
|
||||
} else if (mActionProvider != null) {
|
||||
mActionView = mActionProvider.onCreateActionView();
|
||||
return mActionView;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ActionProvider getActionProvider() {
|
||||
return mActionProvider;
|
||||
}
|
||||
|
||||
public MenuItem setActionProvider(ActionProvider actionProvider) {
|
||||
mActionView = null;
|
||||
mActionProvider = actionProvider;
|
||||
mMenu.onItemsChanged(true); // Measurement can be changed
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShowAsActionFlags(int actionEnum) {
|
||||
setShowAsAction(actionEnum);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expandActionView() {
|
||||
if ((mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) == 0 || mActionView == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mOnActionExpandListener == null ||
|
||||
mOnActionExpandListener.onMenuItemActionExpand(this)) {
|
||||
return mMenu.expandItemActionView(this);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collapseActionView() {
|
||||
if ((mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) == 0) {
|
||||
return false;
|
||||
}
|
||||
if (mActionView == null) {
|
||||
// We're already collapsed if we have no action view.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mOnActionExpandListener == null ||
|
||||
mOnActionExpandListener.onMenuItemActionCollapse(this)) {
|
||||
return mMenu.collapseItemActionView(this);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
|
||||
mOnActionExpandListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean hasCollapsibleActionView() {
|
||||
return (mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) != 0 && mActionView != null;
|
||||
}
|
||||
|
||||
public void setActionViewExpanded(boolean isExpanded) {
|
||||
mIsActionViewExpanded = isExpanded;
|
||||
mMenu.onItemsChanged(false);
|
||||
}
|
||||
|
||||
public boolean isActionViewExpanded() {
|
||||
return mIsActionViewExpanded;
|
||||
}
|
||||
}
|
@ -1,310 +0,0 @@
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.View;
|
||||
import com.actionbarsherlock.internal.view.ActionProviderWrapper;
|
||||
import com.actionbarsherlock.internal.widget.CollapsibleActionViewWrapper;
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import com.actionbarsherlock.view.CollapsibleActionView;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
public class MenuItemWrapper implements MenuItem, android.view.MenuItem.OnMenuItemClickListener {
|
||||
private final android.view.MenuItem mNativeItem;
|
||||
private SubMenu mSubMenu = null;
|
||||
private OnMenuItemClickListener mMenuItemClickListener = null;
|
||||
private OnActionExpandListener mActionExpandListener = null;
|
||||
private android.view.MenuItem.OnActionExpandListener mNativeActionExpandListener = null;
|
||||
|
||||
|
||||
public MenuItemWrapper(android.view.MenuItem nativeItem) {
|
||||
if (nativeItem == null) {
|
||||
throw new IllegalStateException("Wrapped menu item cannot be null.");
|
||||
}
|
||||
mNativeItem = nativeItem;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getItemId() {
|
||||
return mNativeItem.getItemId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupId() {
|
||||
return mNativeItem.getGroupId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return mNativeItem.getOrder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setTitle(CharSequence title) {
|
||||
mNativeItem.setTitle(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setTitle(int title) {
|
||||
mNativeItem.setTitle(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitle() {
|
||||
return mNativeItem.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setTitleCondensed(CharSequence title) {
|
||||
mNativeItem.setTitleCondensed(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitleCondensed() {
|
||||
return mNativeItem.getTitleCondensed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setIcon(Drawable icon) {
|
||||
mNativeItem.setIcon(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setIcon(int iconRes) {
|
||||
mNativeItem.setIcon(iconRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getIcon() {
|
||||
return mNativeItem.getIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setIntent(Intent intent) {
|
||||
mNativeItem.setIntent(intent);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent getIntent() {
|
||||
return mNativeItem.getIntent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShortcut(char numericChar, char alphaChar) {
|
||||
mNativeItem.setShortcut(numericChar, alphaChar);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setNumericShortcut(char numericChar) {
|
||||
mNativeItem.setNumericShortcut(numericChar);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getNumericShortcut() {
|
||||
return mNativeItem.getNumericShortcut();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setAlphabeticShortcut(char alphaChar) {
|
||||
mNativeItem.setAlphabeticShortcut(alphaChar);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getAlphabeticShortcut() {
|
||||
return mNativeItem.getAlphabeticShortcut();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setCheckable(boolean checkable) {
|
||||
mNativeItem.setCheckable(checkable);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCheckable() {
|
||||
return mNativeItem.isCheckable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setChecked(boolean checked) {
|
||||
mNativeItem.setChecked(checked);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return mNativeItem.isChecked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setVisible(boolean visible) {
|
||||
mNativeItem.setVisible(visible);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
return mNativeItem.isVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setEnabled(boolean enabled) {
|
||||
mNativeItem.setEnabled(enabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return mNativeItem.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSubMenu() {
|
||||
return mNativeItem.hasSubMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu getSubMenu() {
|
||||
if (hasSubMenu() && (mSubMenu == null)) {
|
||||
mSubMenu = new SubMenuWrapper(mNativeItem.getSubMenu());
|
||||
}
|
||||
return mSubMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
|
||||
mMenuItemClickListener = menuItemClickListener;
|
||||
//Register ourselves as the listener to proxy
|
||||
mNativeItem.setOnMenuItemClickListener(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(android.view.MenuItem item) {
|
||||
if (mMenuItemClickListener != null) {
|
||||
return mMenuItemClickListener.onMenuItemClick(this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextMenuInfo getMenuInfo() {
|
||||
return mNativeItem.getMenuInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShowAsAction(int actionEnum) {
|
||||
mNativeItem.setShowAsAction(actionEnum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShowAsActionFlags(int actionEnum) {
|
||||
mNativeItem.setShowAsActionFlags(actionEnum);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionView(View view) {
|
||||
if (view != null && view instanceof CollapsibleActionView) {
|
||||
view = new CollapsibleActionViewWrapper(view);
|
||||
}
|
||||
mNativeItem.setActionView(view);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionView(int resId) {
|
||||
//Allow the native menu to inflate the resource
|
||||
mNativeItem.setActionView(resId);
|
||||
if (resId != 0) {
|
||||
//Get newly created view
|
||||
View view = mNativeItem.getActionView();
|
||||
if (view instanceof CollapsibleActionView) {
|
||||
//Wrap it and re-set it
|
||||
mNativeItem.setActionView(new CollapsibleActionViewWrapper(view));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getActionView() {
|
||||
View actionView = mNativeItem.getActionView();
|
||||
if (actionView instanceof CollapsibleActionViewWrapper) {
|
||||
return ((CollapsibleActionViewWrapper)actionView).unwrap();
|
||||
}
|
||||
return actionView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionProvider(ActionProvider actionProvider) {
|
||||
mNativeItem.setActionProvider(new ActionProviderWrapper(actionProvider));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionProvider getActionProvider() {
|
||||
android.view.ActionProvider nativeProvider = mNativeItem.getActionProvider();
|
||||
if (nativeProvider != null && nativeProvider instanceof ActionProviderWrapper) {
|
||||
return ((ActionProviderWrapper)nativeProvider).unwrap();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expandActionView() {
|
||||
return mNativeItem.expandActionView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collapseActionView() {
|
||||
return mNativeItem.collapseActionView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActionViewExpanded() {
|
||||
return mNativeItem.isActionViewExpanded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
|
||||
mActionExpandListener = listener;
|
||||
|
||||
if (mNativeActionExpandListener == null) {
|
||||
mNativeActionExpandListener = new android.view.MenuItem.OnActionExpandListener() {
|
||||
@Override
|
||||
public boolean onMenuItemActionExpand(android.view.MenuItem menuItem) {
|
||||
if (mActionExpandListener != null) {
|
||||
return mActionExpandListener.onMenuItemActionExpand(MenuItemWrapper.this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemActionCollapse(android.view.MenuItem menuItem) {
|
||||
if (mActionExpandListener != null) {
|
||||
return mActionExpandListener.onMenuItemActionCollapse(MenuItemWrapper.this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//Register our inner-class as the listener to proxy method calls
|
||||
mNativeItem.setOnActionExpandListener(mNativeActionExpandListener);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
@ -1,376 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.DataSetObserver;
|
||||
import android.os.Parcelable;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.PopupWindow;
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.view.View_HasStateListenerSupport;
|
||||
import com.actionbarsherlock.internal.view.View_OnAttachStateChangeListener;
|
||||
import com.actionbarsherlock.internal.widget.IcsListPopupWindow;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
/**
|
||||
* Presents a menu as a small, simple popup anchored to another view.
|
||||
* @hide
|
||||
*/
|
||||
public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener,
|
||||
ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener,
|
||||
View_OnAttachStateChangeListener, MenuPresenter {
|
||||
//UNUSED private static final String TAG = "MenuPopupHelper";
|
||||
|
||||
static final int ITEM_LAYOUT = R.layout.abs__popup_menu_item_layout;
|
||||
|
||||
private Context mContext;
|
||||
private LayoutInflater mInflater;
|
||||
private IcsListPopupWindow mPopup;
|
||||
private MenuBuilder mMenu;
|
||||
private int mPopupMaxWidth;
|
||||
private View mAnchorView;
|
||||
private boolean mOverflowOnly;
|
||||
private ViewTreeObserver mTreeObserver;
|
||||
|
||||
private MenuAdapter mAdapter;
|
||||
|
||||
private Callback mPresenterCallback;
|
||||
|
||||
boolean mForceShowIcon;
|
||||
|
||||
private ViewGroup mMeasureParent;
|
||||
|
||||
public MenuPopupHelper(Context context, MenuBuilder menu) {
|
||||
this(context, menu, null, false);
|
||||
}
|
||||
|
||||
public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) {
|
||||
this(context, menu, anchorView, false);
|
||||
}
|
||||
|
||||
public MenuPopupHelper(Context context, MenuBuilder menu,
|
||||
View anchorView, boolean overflowOnly) {
|
||||
mContext = context;
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mMenu = menu;
|
||||
mOverflowOnly = overflowOnly;
|
||||
|
||||
final Resources res = context.getResources();
|
||||
mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
|
||||
res.getDimensionPixelSize(R.dimen.abs__config_prefDialogWidth));
|
||||
|
||||
mAnchorView = anchorView;
|
||||
|
||||
menu.addMenuPresenter(this);
|
||||
}
|
||||
|
||||
public void setAnchorView(View anchor) {
|
||||
mAnchorView = anchor;
|
||||
}
|
||||
|
||||
public void setForceShowIcon(boolean forceShow) {
|
||||
mForceShowIcon = forceShow;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (!tryShow()) {
|
||||
throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean tryShow() {
|
||||
mPopup = new IcsListPopupWindow(mContext, null, R.attr.popupMenuStyle);
|
||||
mPopup.setOnDismissListener(this);
|
||||
mPopup.setOnItemClickListener(this);
|
||||
|
||||
mAdapter = new MenuAdapter(mMenu);
|
||||
mPopup.setAdapter(mAdapter);
|
||||
mPopup.setModal(true);
|
||||
|
||||
View anchor = mAnchorView;
|
||||
if (anchor != null) {
|
||||
final boolean addGlobalListener = mTreeObserver == null;
|
||||
mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest
|
||||
if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
|
||||
((View_HasStateListenerSupport)anchor).addOnAttachStateChangeListener(this);
|
||||
mPopup.setAnchorView(anchor);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
mPopup.setContentWidth(Math.min(measureContentWidth(mAdapter), mPopupMaxWidth));
|
||||
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
|
||||
mPopup.show();
|
||||
mPopup.getListView().setOnKeyListener(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
if (isShowing()) {
|
||||
mPopup.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
public void onDismiss() {
|
||||
mPopup = null;
|
||||
mMenu.close();
|
||||
if (mTreeObserver != null) {
|
||||
if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver();
|
||||
mTreeObserver.removeGlobalOnLayoutListener(this);
|
||||
mTreeObserver = null;
|
||||
}
|
||||
((View_HasStateListenerSupport)mAnchorView).removeOnAttachStateChangeListener(this);
|
||||
}
|
||||
|
||||
public boolean isShowing() {
|
||||
return mPopup != null && mPopup.isShowing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
MenuAdapter adapter = mAdapter;
|
||||
adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
|
||||
}
|
||||
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
dismiss();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private int measureContentWidth(ListAdapter adapter) {
|
||||
// Menus don't tend to be long, so this is more sane than it looks.
|
||||
int width = 0;
|
||||
View itemView = null;
|
||||
int itemType = 0;
|
||||
final int widthMeasureSpec =
|
||||
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
final int heightMeasureSpec =
|
||||
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
final int count = adapter.getCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final int positionType = adapter.getItemViewType(i);
|
||||
if (positionType != itemType) {
|
||||
itemType = positionType;
|
||||
itemView = null;
|
||||
}
|
||||
if (mMeasureParent == null) {
|
||||
mMeasureParent = new FrameLayout(mContext);
|
||||
}
|
||||
itemView = adapter.getView(i, itemView, mMeasureParent);
|
||||
itemView.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
width = Math.max(width, itemView.getMeasuredWidth());
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
if (isShowing()) {
|
||||
final View anchor = mAnchorView;
|
||||
if (anchor == null || !anchor.isShown()) {
|
||||
dismiss();
|
||||
} else if (isShowing()) {
|
||||
// Recompute window size and position
|
||||
mPopup.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
if (mTreeObserver != null) {
|
||||
if (!mTreeObserver.isAlive()) mTreeObserver = v.getViewTreeObserver();
|
||||
mTreeObserver.removeGlobalOnLayoutListener(this);
|
||||
}
|
||||
((View_HasStateListenerSupport)v).removeOnAttachStateChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initForMenu(Context context, MenuBuilder menu) {
|
||||
// Don't need to do anything; we added as a presenter in the constructor.
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuView getMenuView(ViewGroup root) {
|
||||
throw new UnsupportedOperationException("MenuPopupHelpers manage their own views");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMenuView(boolean cleared) {
|
||||
if (mAdapter != null) mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallback(Callback cb) {
|
||||
mPresenterCallback = cb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
|
||||
if (subMenu.hasVisibleItems()) {
|
||||
MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView, false);
|
||||
subPopup.setCallback(mPresenterCallback);
|
||||
|
||||
boolean preserveIconSpacing = false;
|
||||
final int count = subMenu.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
MenuItem childItem = subMenu.getItem(i);
|
||||
if (childItem.isVisible() && childItem.getIcon() != null) {
|
||||
preserveIconSpacing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
subPopup.setForceShowIcon(preserveIconSpacing);
|
||||
|
||||
if (subPopup.tryShow()) {
|
||||
if (mPresenterCallback != null) {
|
||||
mPresenterCallback.onOpenSubMenu(subMenu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||||
// Only care about the (sub)menu we're presenting.
|
||||
if (menu != mMenu) return;
|
||||
|
||||
dismiss();
|
||||
if (mPresenterCallback != null) {
|
||||
mPresenterCallback.onCloseMenu(menu, allMenusAreClosing);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean flagActionItems() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
}
|
||||
|
||||
private class MenuAdapter extends BaseAdapter {
|
||||
private MenuBuilder mAdapterMenu;
|
||||
private int mExpandedIndex = -1;
|
||||
|
||||
public MenuAdapter(MenuBuilder menu) {
|
||||
mAdapterMenu = menu;
|
||||
registerDataSetObserver(new ExpandedIndexObserver());
|
||||
findExpandedIndex();
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
ArrayList<MenuItemImpl> items = mOverflowOnly ?
|
||||
mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
|
||||
if (mExpandedIndex < 0) {
|
||||
return items.size();
|
||||
}
|
||||
return items.size() - 1;
|
||||
}
|
||||
|
||||
public MenuItemImpl getItem(int position) {
|
||||
ArrayList<MenuItemImpl> items = mOverflowOnly ?
|
||||
mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
|
||||
if (mExpandedIndex >= 0 && position >= mExpandedIndex) {
|
||||
position++;
|
||||
}
|
||||
return items.get(position);
|
||||
}
|
||||
|
||||
public long getItemId(int position) {
|
||||
// Since a menu item's ID is optional, we'll use the position as an
|
||||
// ID for the item in the AdapterView
|
||||
return position;
|
||||
}
|
||||
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = mInflater.inflate(ITEM_LAYOUT, parent, false);
|
||||
}
|
||||
|
||||
MenuView.ItemView itemView = (MenuView.ItemView) convertView;
|
||||
if (mForceShowIcon) {
|
||||
((ListMenuItemView) convertView).setForceShowIcon(true);
|
||||
}
|
||||
itemView.initialize(getItem(position), 0);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
void findExpandedIndex() {
|
||||
final MenuItemImpl expandedItem = mMenu.getExpandedItem();
|
||||
if (expandedItem != null) {
|
||||
final ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
|
||||
final int count = items.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final MenuItemImpl item = items.get(i);
|
||||
if (item == expandedItem) {
|
||||
mExpandedIndex = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mExpandedIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private class ExpandedIndexObserver extends DataSetObserver {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
mAdapter.findExpandedIndex();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,148 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 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.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcelable;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* A MenuPresenter is responsible for building views for a Menu object.
|
||||
* It takes over some responsibility from the old style monolithic MenuBuilder class.
|
||||
*/
|
||||
public interface MenuPresenter {
|
||||
/**
|
||||
* Called by menu implementation to notify another component of open/close events.
|
||||
*/
|
||||
public interface Callback {
|
||||
/**
|
||||
* Called when a menu is closing.
|
||||
* @param menu
|
||||
* @param allMenusAreClosing
|
||||
*/
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing);
|
||||
|
||||
/**
|
||||
* Called when a submenu opens. Useful for notifying the application
|
||||
* of menu state so that it does not attempt to hide the action bar
|
||||
* while a submenu is open or similar.
|
||||
*
|
||||
* @param subMenu Submenu currently being opened
|
||||
* @return true if the Callback will handle presenting the submenu, false if
|
||||
* the presenter should attempt to do so.
|
||||
*/
|
||||
public boolean onOpenSubMenu(MenuBuilder subMenu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this presenter for the given context and menu.
|
||||
* This method is called by MenuBuilder when a presenter is
|
||||
* added. See {@link MenuBuilder#addMenuPresenter(MenuPresenter)}
|
||||
*
|
||||
* @param context Context for this presenter; used for view creation and resource management
|
||||
* @param menu Menu to host
|
||||
*/
|
||||
public void initForMenu(Context context, MenuBuilder menu);
|
||||
|
||||
/**
|
||||
* Retrieve a MenuView to display the menu specified in
|
||||
* {@link #initForMenu(Context, Menu)}.
|
||||
*
|
||||
* @param root Intended parent of the MenuView.
|
||||
* @return A freshly created MenuView.
|
||||
*/
|
||||
public MenuView getMenuView(ViewGroup root);
|
||||
|
||||
/**
|
||||
* Update the menu UI in response to a change. Called by
|
||||
* MenuBuilder during the normal course of operation.
|
||||
*
|
||||
* @param cleared true if the menu was entirely cleared
|
||||
*/
|
||||
public void updateMenuView(boolean cleared);
|
||||
|
||||
/**
|
||||
* Set a callback object that will be notified of menu events
|
||||
* related to this specific presentation.
|
||||
* @param cb Callback that will be notified of future events
|
||||
*/
|
||||
public void setCallback(Callback cb);
|
||||
|
||||
/**
|
||||
* Called by Menu implementations to indicate that a submenu item
|
||||
* has been selected. An active Callback should be notified, and
|
||||
* if applicable the presenter should present the submenu.
|
||||
*
|
||||
* @param subMenu SubMenu being opened
|
||||
* @return true if the the event was handled, false otherwise.
|
||||
*/
|
||||
public boolean onSubMenuSelected(SubMenuBuilder subMenu);
|
||||
|
||||
/**
|
||||
* Called by Menu implementations to indicate that a menu or submenu is
|
||||
* closing. Presenter implementations should close the representation
|
||||
* of the menu indicated as necessary and notify a registered callback.
|
||||
*
|
||||
* @param menu Menu or submenu that is closing.
|
||||
* @param allMenusAreClosing True if all associated menus are closing.
|
||||
*/
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing);
|
||||
|
||||
/**
|
||||
* Called by Menu implementations to flag items that will be shown as actions.
|
||||
* @return true if this presenter changed the action status of any items.
|
||||
*/
|
||||
public boolean flagActionItems();
|
||||
|
||||
/**
|
||||
* Called when a menu item with a collapsable action view should expand its action view.
|
||||
*
|
||||
* @param menu Menu containing the item to be expanded
|
||||
* @param item Item to be expanded
|
||||
* @return true if this presenter expanded the action view, false otherwise.
|
||||
*/
|
||||
public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item);
|
||||
|
||||
/**
|
||||
* Called when a menu item with a collapsable action view should collapse its action view.
|
||||
*
|
||||
* @param menu Menu containing the item to be collapsed
|
||||
* @param item Item to be collapsed
|
||||
* @return true if this presenter collapsed the action view, false otherwise.
|
||||
*/
|
||||
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item);
|
||||
|
||||
/**
|
||||
* Returns an ID for determining how to save/restore instance state.
|
||||
* @return a valid ID value.
|
||||
*/
|
||||
public int getId();
|
||||
|
||||
/**
|
||||
* Returns a Parcelable describing the current state of the presenter.
|
||||
* It will be passed to the {@link #onRestoreInstanceState(Parcelable)}
|
||||
* method of the presenter sharing the same ID later.
|
||||
* @return The saved instance state
|
||||
*/
|
||||
public Parcelable onSaveInstanceState();
|
||||
|
||||
/**
|
||||
* Supplies the previously saved instance state to be restored.
|
||||
* @param state The previously saved instance state
|
||||
*/
|
||||
public void onRestoreInstanceState(Parcelable state);
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
/**
|
||||
* Minimal interface for a menu view. {@link #initialize(MenuBuilder)} must be called for the
|
||||
* menu to be functional.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public interface MenuView {
|
||||
/**
|
||||
* Initializes the menu to the given menu. This should be called after the
|
||||
* view is inflated.
|
||||
*
|
||||
* @param menu The menu that this MenuView should display.
|
||||
*/
|
||||
public void initialize(MenuBuilder menu);
|
||||
|
||||
/**
|
||||
* Returns the default animations to be used for this menu when entering/exiting.
|
||||
* @return A resource ID for the default animations to be used for this menu.
|
||||
*/
|
||||
public int getWindowAnimations();
|
||||
|
||||
/**
|
||||
* Minimal interface for a menu item view. {@link #initialize(MenuItemImpl, int)} must be called
|
||||
* for the item to be functional.
|
||||
*/
|
||||
public interface ItemView {
|
||||
/**
|
||||
* Initializes with the provided MenuItemData. This should be called after the view is
|
||||
* inflated.
|
||||
* @param itemData The item that this ItemView should display.
|
||||
* @param menuType The type of this menu, one of
|
||||
* {@link MenuBuilder#TYPE_ICON}, {@link MenuBuilder#TYPE_EXPANDED},
|
||||
* {@link MenuBuilder#TYPE_DIALOG}).
|
||||
*/
|
||||
public void initialize(MenuItemImpl itemData, int menuType);
|
||||
|
||||
/**
|
||||
* Gets the item data that this view is displaying.
|
||||
* @return the item data, or null if there is not one
|
||||
*/
|
||||
public MenuItemImpl getItemData();
|
||||
|
||||
/**
|
||||
* Sets the title of the item view.
|
||||
* @param title The title to set.
|
||||
*/
|
||||
public void setTitle(CharSequence title);
|
||||
|
||||
/**
|
||||
* Sets the enabled state of the item view.
|
||||
* @param enabled Whether the item view should be enabled.
|
||||
*/
|
||||
public void setEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Displays the checkbox for the item view. This does not ensure the item view will be
|
||||
* checked, for that use {@link #setChecked}.
|
||||
* @param checkable Whether to display the checkbox or to hide it
|
||||
*/
|
||||
public void setCheckable(boolean checkable);
|
||||
|
||||
/**
|
||||
* Checks the checkbox for the item view. If the checkbox is hidden, it will NOT be
|
||||
* made visible, call {@link #setCheckable(boolean)} for that.
|
||||
* @param checked Whether the checkbox should be checked
|
||||
*/
|
||||
public void setChecked(boolean checked);
|
||||
|
||||
/**
|
||||
* Sets the shortcut for the item.
|
||||
* @param showShortcut Whether a shortcut should be shown(if false, the value of
|
||||
* shortcutKey should be ignored).
|
||||
* @param shortcutKey The shortcut key that should be shown on the ItemView.
|
||||
*/
|
||||
public void setShortcut(boolean showShortcut, char shortcutKey);
|
||||
|
||||
/**
|
||||
* Set the icon of this item view.
|
||||
* @param icon The icon of this item. null to hide the icon.
|
||||
*/
|
||||
public void setIcon(Drawable icon);
|
||||
|
||||
/**
|
||||
* Whether this item view prefers displaying the condensed title rather
|
||||
* than the normal title. If a condensed title is not available, the
|
||||
* normal title will be used.
|
||||
*
|
||||
* @return Whether this item view prefers displaying the condensed
|
||||
* title.
|
||||
*/
|
||||
public boolean prefersCondensedTitle();
|
||||
|
||||
/**
|
||||
* Whether this item view shows an icon.
|
||||
*
|
||||
* @return Whether this item view shows an icon.
|
||||
*/
|
||||
public boolean showsIcon();
|
||||
}
|
||||
}
|
@ -1,185 +0,0 @@
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import java.util.WeakHashMap;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.view.KeyEvent;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
public class MenuWrapper implements Menu {
|
||||
private final android.view.Menu mNativeMenu;
|
||||
|
||||
private final WeakHashMap<android.view.MenuItem, MenuItem> mNativeMap =
|
||||
new WeakHashMap<android.view.MenuItem, MenuItem>();
|
||||
|
||||
|
||||
public MenuWrapper(android.view.Menu nativeMenu) {
|
||||
mNativeMenu = nativeMenu;
|
||||
}
|
||||
|
||||
public android.view.Menu unwrap() {
|
||||
return mNativeMenu;
|
||||
}
|
||||
|
||||
private MenuItem addInternal(android.view.MenuItem nativeItem) {
|
||||
MenuItem item = new MenuItemWrapper(nativeItem);
|
||||
mNativeMap.put(nativeItem, item);
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(CharSequence title) {
|
||||
return addInternal(mNativeMenu.add(title));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(int titleRes) {
|
||||
return addInternal(mNativeMenu.add(titleRes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
|
||||
return addInternal(mNativeMenu.add(groupId, itemId, order, title));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(int groupId, int itemId, int order, int titleRes) {
|
||||
return addInternal(mNativeMenu.add(groupId, itemId, order, titleRes));
|
||||
}
|
||||
|
||||
private SubMenu addInternal(android.view.SubMenu nativeSubMenu) {
|
||||
SubMenu subMenu = new SubMenuWrapper(nativeSubMenu);
|
||||
android.view.MenuItem nativeItem = nativeSubMenu.getItem();
|
||||
MenuItem item = subMenu.getItem();
|
||||
mNativeMap.put(nativeItem, item);
|
||||
return subMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(CharSequence title) {
|
||||
return addInternal(mNativeMenu.addSubMenu(title));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(int titleRes) {
|
||||
return addInternal(mNativeMenu.addSubMenu(titleRes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) {
|
||||
return addInternal(mNativeMenu.addSubMenu(groupId, itemId, order, title));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
|
||||
return addInternal(mNativeMenu.addSubMenu(groupId, itemId, order, titleRes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int addIntentOptions(int groupId, int itemId, int order, ComponentName caller, Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) {
|
||||
int result;
|
||||
if (outSpecificItems != null) {
|
||||
android.view.MenuItem[] nativeOutItems = new android.view.MenuItem[outSpecificItems.length];
|
||||
result = mNativeMenu.addIntentOptions(groupId, itemId, order, caller, specifics, intent, flags, nativeOutItems);
|
||||
for (int i = 0, length = outSpecificItems.length; i < length; i++) {
|
||||
outSpecificItems[i] = new MenuItemWrapper(nativeOutItems[i]);
|
||||
}
|
||||
} else {
|
||||
result = mNativeMenu.addIntentOptions(groupId, itemId, order, caller, specifics, intent, flags, null);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeItem(int id) {
|
||||
mNativeMenu.removeItem(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGroup(int groupId) {
|
||||
mNativeMenu.removeGroup(groupId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
mNativeMap.clear();
|
||||
mNativeMenu.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupCheckable(int group, boolean checkable, boolean exclusive) {
|
||||
mNativeMenu.setGroupCheckable(group, checkable, exclusive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupVisible(int group, boolean visible) {
|
||||
mNativeMenu.setGroupVisible(group, visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupEnabled(int group, boolean enabled) {
|
||||
mNativeMenu.setGroupEnabled(group, enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasVisibleItems() {
|
||||
return mNativeMenu.hasVisibleItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem findItem(int id) {
|
||||
android.view.MenuItem nativeItem = mNativeMenu.findItem(id);
|
||||
return findItem(nativeItem);
|
||||
}
|
||||
|
||||
public MenuItem findItem(android.view.MenuItem nativeItem) {
|
||||
if (nativeItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MenuItem wrapped = mNativeMap.get(nativeItem);
|
||||
if (wrapped != null) {
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
return addInternal(nativeItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return mNativeMenu.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem getItem(int index) {
|
||||
android.view.MenuItem nativeItem = mNativeMenu.getItem(index);
|
||||
return findItem(nativeItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
mNativeMenu.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
|
||||
return mNativeMenu.performShortcut(keyCode, event, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShortcutKey(int keyCode, KeyEvent event) {
|
||||
return mNativeMenu.isShortcutKey(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performIdentifierAction(int id, int flags) {
|
||||
return mNativeMenu.performIdentifierAction(id, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQwertyMode(boolean isQwerty) {
|
||||
mNativeMenu.setQwertyMode(isQwerty);
|
||||
}
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
/**
|
||||
* The model for a sub menu, which is an extension of the menu. Most methods are proxied to
|
||||
* the parent menu.
|
||||
*/
|
||||
public class SubMenuBuilder extends MenuBuilder implements SubMenu {
|
||||
private MenuBuilder mParentMenu;
|
||||
private MenuItemImpl mItem;
|
||||
|
||||
public SubMenuBuilder(Context context, MenuBuilder parentMenu, MenuItemImpl item) {
|
||||
super(context);
|
||||
|
||||
mParentMenu = parentMenu;
|
||||
mItem = item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQwertyMode(boolean isQwerty) {
|
||||
mParentMenu.setQwertyMode(isQwerty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQwertyMode() {
|
||||
return mParentMenu.isQwertyMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShortcutsVisible(boolean shortcutsVisible) {
|
||||
mParentMenu.setShortcutsVisible(shortcutsVisible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShortcutsVisible() {
|
||||
return mParentMenu.isShortcutsVisible();
|
||||
}
|
||||
|
||||
public Menu getParentMenu() {
|
||||
return mParentMenu;
|
||||
}
|
||||
|
||||
public MenuItem getItem() {
|
||||
return mItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallback(Callback callback) {
|
||||
mParentMenu.setCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuBuilder getRootMenu() {
|
||||
return mParentMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean dispatchMenuItemSelected(MenuBuilder menu, MenuItem item) {
|
||||
return super.dispatchMenuItemSelected(menu, item) ||
|
||||
mParentMenu.dispatchMenuItemSelected(menu, item);
|
||||
}
|
||||
|
||||
public SubMenu setIcon(Drawable icon) {
|
||||
mItem.setIcon(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SubMenu setIcon(int iconRes) {
|
||||
mItem.setIcon(iconRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SubMenu setHeaderIcon(Drawable icon) {
|
||||
return (SubMenu) super.setHeaderIconInt(icon);
|
||||
}
|
||||
|
||||
public SubMenu setHeaderIcon(int iconRes) {
|
||||
return (SubMenu) super.setHeaderIconInt(iconRes);
|
||||
}
|
||||
|
||||
public SubMenu setHeaderTitle(CharSequence title) {
|
||||
return (SubMenu) super.setHeaderTitleInt(title);
|
||||
}
|
||||
|
||||
public SubMenu setHeaderTitle(int titleRes) {
|
||||
return (SubMenu) super.setHeaderTitleInt(titleRes);
|
||||
}
|
||||
|
||||
public SubMenu setHeaderView(View view) {
|
||||
return (SubMenu) super.setHeaderViewInt(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expandItemActionView(MenuItemImpl item) {
|
||||
return mParentMenu.expandItemActionView(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collapseItemActionView(MenuItemImpl item) {
|
||||
return mParentMenu.collapseItemActionView(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActionViewStatesKey() {
|
||||
final int itemId = mItem != null ? mItem.getItemId() : 0;
|
||||
if (itemId == 0) {
|
||||
return null;
|
||||
}
|
||||
return super.getActionViewStatesKey() + ":" + itemId;
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
public class SubMenuWrapper extends MenuWrapper implements SubMenu {
|
||||
private final android.view.SubMenu mNativeSubMenu;
|
||||
private MenuItem mItem = null;
|
||||
|
||||
public SubMenuWrapper(android.view.SubMenu nativeSubMenu) {
|
||||
super(nativeSubMenu);
|
||||
mNativeSubMenu = nativeSubMenu;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderTitle(int titleRes) {
|
||||
mNativeSubMenu.setHeaderTitle(titleRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderTitle(CharSequence title) {
|
||||
mNativeSubMenu.setHeaderTitle(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderIcon(int iconRes) {
|
||||
mNativeSubMenu.setHeaderIcon(iconRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderIcon(Drawable icon) {
|
||||
mNativeSubMenu.setHeaderIcon(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderView(View view) {
|
||||
mNativeSubMenu.setHeaderView(view);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearHeader() {
|
||||
mNativeSubMenu.clearHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setIcon(int iconRes) {
|
||||
mNativeSubMenu.setIcon(iconRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setIcon(Drawable icon) {
|
||||
mNativeSubMenu.setIcon(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem getItem() {
|
||||
if (mItem == null) {
|
||||
mItem = new MenuItemWrapper(mNativeSubMenu.getItem());
|
||||
}
|
||||
return mItem;
|
||||
}
|
||||
}
|
@ -1,291 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 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.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Animator;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.AnimatorSet;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.view.NineViewGroup;
|
||||
import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter;
|
||||
import com.actionbarsherlock.internal.view.menu.ActionMenuView;
|
||||
|
||||
import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean;
|
||||
|
||||
public abstract class AbsActionBarView extends NineViewGroup {
|
||||
protected ActionMenuView mMenuView;
|
||||
protected ActionMenuPresenter mActionMenuPresenter;
|
||||
protected ActionBarContainer mSplitView;
|
||||
protected boolean mSplitActionBar;
|
||||
protected boolean mSplitWhenNarrow;
|
||||
protected int mContentHeight;
|
||||
|
||||
final Context mContext;
|
||||
|
||||
protected Animator mVisibilityAnim;
|
||||
protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
|
||||
|
||||
private static final /*Time*/Interpolator sAlphaInterpolator = new DecelerateInterpolator();
|
||||
|
||||
private static final int FADE_DURATION = 200;
|
||||
|
||||
public AbsActionBarView(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public AbsActionBarView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public AbsActionBarView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be public so we can dispatch pre-2.2 via ActionBarImpl.
|
||||
*/
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
} else if (mMenuView != null) {
|
||||
mMenuView.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
// Action bar can change size on configuration changes.
|
||||
// Reread the desired height from the theme-specified style.
|
||||
TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.SherlockActionBar,
|
||||
R.attr.actionBarStyle, 0);
|
||||
setContentHeight(a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0));
|
||||
a.recycle();
|
||||
if (mSplitWhenNarrow) {
|
||||
setSplitActionBar(getResources_getBoolean(getContext(),
|
||||
R.bool.abs__split_action_bar_is_narrow));
|
||||
}
|
||||
if (mActionMenuPresenter != null) {
|
||||
mActionMenuPresenter.onConfigurationChanged(newConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the bar should be split right now, no questions asked.
|
||||
* @param split true if the bar should split
|
||||
*/
|
||||
public void setSplitActionBar(boolean split) {
|
||||
mSplitActionBar = split;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the bar should split if we enter a narrow screen configuration.
|
||||
* @param splitWhenNarrow true if the bar should check to split after a config change
|
||||
*/
|
||||
public void setSplitWhenNarrow(boolean splitWhenNarrow) {
|
||||
mSplitWhenNarrow = splitWhenNarrow;
|
||||
}
|
||||
|
||||
public void setContentHeight(int height) {
|
||||
mContentHeight = height;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
public int getContentHeight() {
|
||||
return mContentHeight;
|
||||
}
|
||||
|
||||
public void setSplitView(ActionBarContainer splitView) {
|
||||
mSplitView = splitView;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current visibility or if animating, the visibility being animated to.
|
||||
*/
|
||||
public int getAnimatedVisibility() {
|
||||
if (mVisibilityAnim != null) {
|
||||
return mVisAnimListener.mFinalVisibility;
|
||||
}
|
||||
return getVisibility();
|
||||
}
|
||||
|
||||
public void animateToVisibility(int visibility) {
|
||||
if (mVisibilityAnim != null) {
|
||||
mVisibilityAnim.cancel();
|
||||
}
|
||||
if (visibility == VISIBLE) {
|
||||
if (getVisibility() != VISIBLE) {
|
||||
setAlpha(0);
|
||||
if (mSplitView != null && mMenuView != null) {
|
||||
mMenuView.setAlpha(0);
|
||||
}
|
||||
}
|
||||
ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1);
|
||||
anim.setDuration(FADE_DURATION);
|
||||
anim.setInterpolator(sAlphaInterpolator);
|
||||
if (mSplitView != null && mMenuView != null) {
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 1);
|
||||
splitAnim.setDuration(FADE_DURATION);
|
||||
set.addListener(mVisAnimListener.withFinalVisibility(visibility));
|
||||
set.play(anim).with(splitAnim);
|
||||
set.start();
|
||||
} else {
|
||||
anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
|
||||
anim.start();
|
||||
}
|
||||
} else {
|
||||
ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0);
|
||||
anim.setDuration(FADE_DURATION);
|
||||
anim.setInterpolator(sAlphaInterpolator);
|
||||
if (mSplitView != null && mMenuView != null) {
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 0);
|
||||
splitAnim.setDuration(FADE_DURATION);
|
||||
set.addListener(mVisAnimListener.withFinalVisibility(visibility));
|
||||
set.play(anim).with(splitAnim);
|
||||
set.start();
|
||||
} else {
|
||||
anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
|
||||
anim.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
if (mVisibilityAnim != null) {
|
||||
mVisibilityAnim.end();
|
||||
}
|
||||
super.setVisibility(visibility);
|
||||
}
|
||||
|
||||
public boolean showOverflowMenu() {
|
||||
if (mActionMenuPresenter != null) {
|
||||
return mActionMenuPresenter.showOverflowMenu();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void postShowOverflowMenu() {
|
||||
post(new Runnable() {
|
||||
public void run() {
|
||||
showOverflowMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean hideOverflowMenu() {
|
||||
if (mActionMenuPresenter != null) {
|
||||
return mActionMenuPresenter.hideOverflowMenu();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isOverflowMenuShowing() {
|
||||
if (mActionMenuPresenter != null) {
|
||||
return mActionMenuPresenter.isOverflowMenuShowing();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isOverflowReserved() {
|
||||
return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved();
|
||||
}
|
||||
|
||||
public void dismissPopupMenus() {
|
||||
if (mActionMenuPresenter != null) {
|
||||
mActionMenuPresenter.dismissPopupMenus();
|
||||
}
|
||||
}
|
||||
|
||||
protected int measureChildView(View child, int availableWidth, int childSpecHeight,
|
||||
int spacing) {
|
||||
child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
|
||||
childSpecHeight);
|
||||
|
||||
availableWidth -= child.getMeasuredWidth();
|
||||
availableWidth -= spacing;
|
||||
|
||||
return Math.max(0, availableWidth);
|
||||
}
|
||||
|
||||
protected 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;
|
||||
}
|
||||
|
||||
protected 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;
|
||||
}
|
||||
|
||||
protected class VisibilityAnimListener implements Animator.AnimatorListener {
|
||||
private boolean mCanceled = false;
|
||||
int mFinalVisibility;
|
||||
|
||||
public VisibilityAnimListener withFinalVisibility(int visibility) {
|
||||
mFinalVisibility = visibility;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
setVisibility(VISIBLE);
|
||||
mVisibilityAnim = animation;
|
||||
mCanceled = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mCanceled) return;
|
||||
|
||||
mVisibilityAnim = null;
|
||||
setVisibility(mFinalVisibility);
|
||||
if (mSplitView != null && mMenuView != null) {
|
||||
mMenuView.setVisibility(mFinalVisibility);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
mCanceled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
}
|
||||
}
|
||||
}
|
@ -1,258 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.app.ActionBar;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout;
|
||||
|
||||
/**
|
||||
* This class acts as a container for the action bar view and action mode context views.
|
||||
* It applies special styles as needed to help handle animated transitions between them.
|
||||
* @hide
|
||||
*/
|
||||
public class ActionBarContainer extends NineFrameLayout {
|
||||
private boolean mIsTransitioning;
|
||||
private View mTabContainer;
|
||||
private ActionBarView mActionBarView;
|
||||
|
||||
private Drawable mBackground;
|
||||
private Drawable mStackedBackground;
|
||||
private Drawable mSplitBackground;
|
||||
private boolean mIsSplit;
|
||||
private boolean mIsStacked;
|
||||
|
||||
public ActionBarContainer(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ActionBarContainer(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
setBackgroundDrawable(null);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
R.styleable.SherlockActionBar);
|
||||
mBackground = a.getDrawable(R.styleable.SherlockActionBar_background);
|
||||
mStackedBackground = a.getDrawable(
|
||||
R.styleable.SherlockActionBar_backgroundStacked);
|
||||
|
||||
//Fix for issue #379
|
||||
if (mStackedBackground instanceof ColorDrawable && Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||||
Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
|
||||
Canvas c = new Canvas(bitmap);
|
||||
mStackedBackground.draw(c);
|
||||
int color = bitmap.getPixel(0, 0);
|
||||
bitmap.recycle();
|
||||
mStackedBackground = new IcsColorDrawable(color);
|
||||
}
|
||||
|
||||
if (getId() == R.id.abs__split_action_bar) {
|
||||
mIsSplit = true;
|
||||
mSplitBackground = a.getDrawable(
|
||||
R.styleable.SherlockActionBar_backgroundSplit);
|
||||
}
|
||||
a.recycle();
|
||||
|
||||
setWillNotDraw(mIsSplit ? mSplitBackground == null :
|
||||
mBackground == null && mStackedBackground == null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mActionBarView = (ActionBarView) findViewById(R.id.abs__action_bar);
|
||||
}
|
||||
|
||||
public void setPrimaryBackground(Drawable bg) {
|
||||
mBackground = bg;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setStackedBackground(Drawable bg) {
|
||||
mStackedBackground = bg;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setSplitBackground(Drawable bg) {
|
||||
mSplitBackground = bg;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the action bar into a "transitioning" state. While transitioning
|
||||
* the bar will block focus and touch from all of its descendants. This
|
||||
* prevents the user from interacting with the bar while it is animating
|
||||
* in or out.
|
||||
*
|
||||
* @param isTransitioning true if the bar is currently transitioning, false otherwise.
|
||||
*/
|
||||
public void setTransitioning(boolean isTransitioning) {
|
||||
mIsTransitioning = isTransitioning;
|
||||
setDescendantFocusability(isTransitioning ? FOCUS_BLOCK_DESCENDANTS
|
||||
: FOCUS_AFTER_DESCENDANTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
return mIsTransitioning || super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
super.onTouchEvent(ev);
|
||||
|
||||
// An action bar always eats touch events.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHoverEvent(MotionEvent ev) {
|
||||
super.onHoverEvent(ev);
|
||||
|
||||
// An action bar always eats hover events.
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setTabContainer(ScrollingTabContainerView tabView) {
|
||||
if (mTabContainer != null) {
|
||||
removeView(mTabContainer);
|
||||
}
|
||||
mTabContainer = tabView;
|
||||
if (tabView != null) {
|
||||
addView(tabView);
|
||||
final ViewGroup.LayoutParams lp = tabView.getLayoutParams();
|
||||
lp.width = LayoutParams.MATCH_PARENT;
|
||||
lp.height = LayoutParams.WRAP_CONTENT;
|
||||
tabView.setAllowCollapse(false);
|
||||
}
|
||||
}
|
||||
|
||||
public View getTabContainer() {
|
||||
return mTabContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas) {
|
||||
if (getWidth() == 0 || getHeight() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsSplit) {
|
||||
if (mSplitBackground != null) mSplitBackground.draw(canvas);
|
||||
} else {
|
||||
if (mBackground != null) {
|
||||
mBackground.draw(canvas);
|
||||
}
|
||||
if (mStackedBackground != null && mIsStacked) {
|
||||
mStackedBackground.draw(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//This causes the animation reflection to fail on pre-HC platforms
|
||||
//@Override
|
||||
//public android.view.ActionMode startActionModeForChild(View child, android.view.ActionMode.Callback callback) {
|
||||
// // No starting an action mode for an action bar child! (Where would it go?)
|
||||
// return null;
|
||||
//}
|
||||
|
||||
@Override
|
||||
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
if (mActionBarView == null) return;
|
||||
|
||||
final LayoutParams lp = (LayoutParams) mActionBarView.getLayoutParams();
|
||||
final int actionBarViewHeight = mActionBarView.isCollapsed() ? 0 :
|
||||
mActionBarView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
|
||||
|
||||
if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
|
||||
final int mode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
if (mode == MeasureSpec.AT_MOST) {
|
||||
final int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
|
||||
setMeasuredDimension(getMeasuredWidth(),
|
||||
Math.min(actionBarViewHeight + mTabContainer.getMeasuredHeight(),
|
||||
maxHeight));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
super.onLayout(changed, l, t, r, b);
|
||||
|
||||
final boolean hasTabs = mTabContainer != null && mTabContainer.getVisibility() != GONE;
|
||||
|
||||
if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
|
||||
final int containerHeight = getMeasuredHeight();
|
||||
final int tabHeight = mTabContainer.getMeasuredHeight();
|
||||
|
||||
if ((mActionBarView.getDisplayOptions() & ActionBar.DISPLAY_SHOW_HOME) == 0) {
|
||||
// Not showing home, put tabs on top.
|
||||
final int count = getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
|
||||
if (child == mTabContainer) continue;
|
||||
|
||||
if (!mActionBarView.isCollapsed()) {
|
||||
child.offsetTopAndBottom(tabHeight);
|
||||
}
|
||||
}
|
||||
mTabContainer.layout(l, 0, r, tabHeight);
|
||||
} else {
|
||||
mTabContainer.layout(l, containerHeight - tabHeight, r, containerHeight);
|
||||
}
|
||||
}
|
||||
|
||||
boolean needsInvalidate = false;
|
||||
if (mIsSplit) {
|
||||
if (mSplitBackground != null) {
|
||||
mSplitBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
|
||||
needsInvalidate = true;
|
||||
}
|
||||
} else {
|
||||
if (mBackground != null) {
|
||||
mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(),
|
||||
mActionBarView.getRight(), mActionBarView.getBottom());
|
||||
needsInvalidate = true;
|
||||
}
|
||||
if ((mIsStacked = hasTabs && mStackedBackground != null)) {
|
||||
mStackedBackground.setBounds(mTabContainer.getLeft(), mTabContainer.getTop(),
|
||||
mTabContainer.getRight(), mTabContainer.getBottom());
|
||||
needsInvalidate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsInvalidate) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,518 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Animator;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Animator.AnimatorListener;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.AnimatorSet;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout;
|
||||
import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter;
|
||||
import com.actionbarsherlock.internal.view.menu.ActionMenuView;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuBuilder;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ActionBarContextView extends AbsActionBarView implements AnimatorListener {
|
||||
//UNUSED private static final String TAG = "ActionBarContextView";
|
||||
|
||||
private CharSequence mTitle;
|
||||
private CharSequence mSubtitle;
|
||||
|
||||
private NineLinearLayout mClose;
|
||||
private View mCustomView;
|
||||
private LinearLayout mTitleLayout;
|
||||
private TextView mTitleView;
|
||||
private TextView mSubtitleView;
|
||||
private int mTitleStyleRes;
|
||||
private int mSubtitleStyleRes;
|
||||
private Drawable mSplitBackground;
|
||||
|
||||
private Animator mCurrentAnimation;
|
||||
private boolean mAnimateInOnLayout;
|
||||
private int mAnimationMode;
|
||||
|
||||
private static final int ANIMATE_IDLE = 0;
|
||||
private static final int ANIMATE_IN = 1;
|
||||
private static final int ANIMATE_OUT = 2;
|
||||
|
||||
public ActionBarContextView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ActionBarContextView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, R.attr.actionModeStyle);
|
||||
}
|
||||
|
||||
public ActionBarContextView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SherlockActionMode, defStyle, 0);
|
||||
setBackgroundDrawable(a.getDrawable(
|
||||
R.styleable.SherlockActionMode_background));
|
||||
mTitleStyleRes = a.getResourceId(
|
||||
R.styleable.SherlockActionMode_titleTextStyle, 0);
|
||||
mSubtitleStyleRes = a.getResourceId(
|
||||
R.styleable.SherlockActionMode_subtitleTextStyle, 0);
|
||||
|
||||
mContentHeight = a.getLayoutDimension(
|
||||
R.styleable.SherlockActionMode_height, 0);
|
||||
|
||||
mSplitBackground = a.getDrawable(
|
||||
R.styleable.SherlockActionMode_backgroundSplit);
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if (mActionMenuPresenter != null) {
|
||||
mActionMenuPresenter.hideOverflowMenu();
|
||||
mActionMenuPresenter.hideSubMenus();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSplitActionBar(boolean split) {
|
||||
if (mSplitActionBar != split) {
|
||||
if (mActionMenuPresenter != null) {
|
||||
// Mode is already active; move everything over and adjust the menu itself.
|
||||
final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.MATCH_PARENT);
|
||||
if (!split) {
|
||||
mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
|
||||
mMenuView.setBackgroundDrawable(null);
|
||||
final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
|
||||
if (oldParent != null) oldParent.removeView(mMenuView);
|
||||
addView(mMenuView, layoutParams);
|
||||
} else {
|
||||
// Allow full screen width in split mode.
|
||||
mActionMenuPresenter.setWidthLimit(
|
||||
getContext().getResources().getDisplayMetrics().widthPixels, true);
|
||||
// No limit to the item count; use whatever will fit.
|
||||
mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
|
||||
// Span the whole width
|
||||
layoutParams.width = LayoutParams.MATCH_PARENT;
|
||||
layoutParams.height = mContentHeight;
|
||||
mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
|
||||
mMenuView.setBackgroundDrawable(mSplitBackground);
|
||||
final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
|
||||
if (oldParent != null) oldParent.removeView(mMenuView);
|
||||
mSplitView.addView(mMenuView, layoutParams);
|
||||
}
|
||||
}
|
||||
super.setSplitActionBar(split);
|
||||
}
|
||||
}
|
||||
|
||||
public void setContentHeight(int height) {
|
||||
mContentHeight = height;
|
||||
}
|
||||
|
||||
public void setCustomView(View view) {
|
||||
if (mCustomView != null) {
|
||||
removeView(mCustomView);
|
||||
}
|
||||
mCustomView = view;
|
||||
if (mTitleLayout != null) {
|
||||
removeView(mTitleLayout);
|
||||
mTitleLayout = null;
|
||||
}
|
||||
if (view != null) {
|
||||
addView(view);
|
||||
}
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence title) {
|
||||
mTitle = title;
|
||||
initTitle();
|
||||
}
|
||||
|
||||
public void setSubtitle(CharSequence subtitle) {
|
||||
mSubtitle = subtitle;
|
||||
initTitle();
|
||||
}
|
||||
|
||||
public CharSequence getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
public CharSequence getSubtitle() {
|
||||
return mSubtitle;
|
||||
}
|
||||
|
||||
private void initTitle() {
|
||||
if (mTitleLayout == null) {
|
||||
LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||
inflater.inflate(R.layout.abs__action_bar_title_item, this);
|
||||
mTitleLayout = (LinearLayout) getChildAt(getChildCount() - 1);
|
||||
mTitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_title);
|
||||
mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_subtitle);
|
||||
if (mTitleStyleRes != 0) {
|
||||
mTitleView.setTextAppearance(mContext, mTitleStyleRes);
|
||||
}
|
||||
if (mSubtitleStyleRes != 0) {
|
||||
mSubtitleView.setTextAppearance(mContext, mSubtitleStyleRes);
|
||||
}
|
||||
}
|
||||
|
||||
mTitleView.setText(mTitle);
|
||||
mSubtitleView.setText(mSubtitle);
|
||||
|
||||
final boolean hasTitle = !TextUtils.isEmpty(mTitle);
|
||||
final boolean hasSubtitle = !TextUtils.isEmpty(mSubtitle);
|
||||
mSubtitleView.setVisibility(hasSubtitle ? VISIBLE : GONE);
|
||||
mTitleLayout.setVisibility(hasTitle || hasSubtitle ? VISIBLE : GONE);
|
||||
if (mTitleLayout.getParent() == null) {
|
||||
addView(mTitleLayout);
|
||||
}
|
||||
}
|
||||
|
||||
public void initForMode(final ActionMode mode) {
|
||||
if (mClose == null) {
|
||||
LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||
mClose = (NineLinearLayout)inflater.inflate(R.layout.abs__action_mode_close_item, this, false);
|
||||
addView(mClose);
|
||||
} else if (mClose.getParent() == null) {
|
||||
addView(mClose);
|
||||
}
|
||||
|
||||
View closeButton = mClose.findViewById(R.id.abs__action_mode_close_button);
|
||||
closeButton.setOnClickListener(new OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
mode.finish();
|
||||
}
|
||||
});
|
||||
|
||||
final MenuBuilder menu = (MenuBuilder) mode.getMenu();
|
||||
if (mActionMenuPresenter != null) {
|
||||
mActionMenuPresenter.dismissPopupMenus();
|
||||
}
|
||||
mActionMenuPresenter = new ActionMenuPresenter(mContext);
|
||||
mActionMenuPresenter.setReserveOverflow(true);
|
||||
|
||||
final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.MATCH_PARENT);
|
||||
if (!mSplitActionBar) {
|
||||
menu.addMenuPresenter(mActionMenuPresenter);
|
||||
mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
|
||||
mMenuView.setBackgroundDrawable(null);
|
||||
addView(mMenuView, layoutParams);
|
||||
} else {
|
||||
// Allow full screen width in split mode.
|
||||
mActionMenuPresenter.setWidthLimit(
|
||||
getContext().getResources().getDisplayMetrics().widthPixels, true);
|
||||
// No limit to the item count; use whatever will fit.
|
||||
mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
|
||||
// Span the whole width
|
||||
layoutParams.width = LayoutParams.MATCH_PARENT;
|
||||
layoutParams.height = mContentHeight;
|
||||
menu.addMenuPresenter(mActionMenuPresenter);
|
||||
mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
|
||||
mMenuView.setBackgroundDrawable(mSplitBackground);
|
||||
mSplitView.addView(mMenuView, layoutParams);
|
||||
}
|
||||
|
||||
mAnimateInOnLayout = true;
|
||||
}
|
||||
|
||||
public void closeMode() {
|
||||
if (mAnimationMode == ANIMATE_OUT) {
|
||||
// Called again during close; just finish what we were doing.
|
||||
return;
|
||||
}
|
||||
if (mClose == null) {
|
||||
killMode();
|
||||
return;
|
||||
}
|
||||
|
||||
finishAnimation();
|
||||
mAnimationMode = ANIMATE_OUT;
|
||||
mCurrentAnimation = makeOutAnimation();
|
||||
mCurrentAnimation.start();
|
||||
}
|
||||
|
||||
private void finishAnimation() {
|
||||
final Animator a = mCurrentAnimation;
|
||||
if (a != null) {
|
||||
mCurrentAnimation = null;
|
||||
a.end();
|
||||
}
|
||||
}
|
||||
|
||||
public void killMode() {
|
||||
finishAnimation();
|
||||
removeAllViews();
|
||||
if (mSplitView != null) {
|
||||
mSplitView.removeView(mMenuView);
|
||||
}
|
||||
mCustomView = null;
|
||||
mMenuView = null;
|
||||
mAnimateInOnLayout = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showOverflowMenu() {
|
||||
if (mActionMenuPresenter != null) {
|
||||
return mActionMenuPresenter.showOverflowMenu();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hideOverflowMenu() {
|
||||
if (mActionMenuPresenter != null) {
|
||||
return mActionMenuPresenter.hideOverflowMenu();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverflowMenuShowing() {
|
||||
if (mActionMenuPresenter != null) {
|
||||
return mActionMenuPresenter.isOverflowMenuShowing();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
|
||||
// Used by custom views if they don't supply layout params. Everything else
|
||||
// added to an ActionBarContextView should have them already.
|
||||
return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
|
||||
return new MarginLayoutParams(getContext(), attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
final 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)");
|
||||
}
|
||||
|
||||
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
if (heightMode == MeasureSpec.UNSPECIFIED) {
|
||||
throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
|
||||
"with android:layout_height=\"wrap_content\"");
|
||||
}
|
||||
|
||||
final int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
|
||||
|
||||
int maxHeight = mContentHeight > 0 ?
|
||||
mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
|
||||
|
||||
final int verticalPadding = getPaddingTop() + getPaddingBottom();
|
||||
int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
|
||||
final int height = maxHeight - verticalPadding;
|
||||
final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
|
||||
|
||||
if (mClose != null) {
|
||||
availableWidth = measureChildView(mClose, availableWidth, childSpecHeight, 0);
|
||||
MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams();
|
||||
availableWidth -= lp.leftMargin + lp.rightMargin;
|
||||
}
|
||||
|
||||
if (mMenuView != null && mMenuView.getParent() == this) {
|
||||
availableWidth = measureChildView(mMenuView, availableWidth,
|
||||
childSpecHeight, 0);
|
||||
}
|
||||
|
||||
if (mTitleLayout != null && mCustomView == null) {
|
||||
availableWidth = measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
|
||||
}
|
||||
|
||||
if (mCustomView != null) {
|
||||
ViewGroup.LayoutParams lp = mCustomView.getLayoutParams();
|
||||
final int customWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
|
||||
MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
|
||||
final int customWidth = lp.width >= 0 ?
|
||||
Math.min(lp.width, availableWidth) : availableWidth;
|
||||
final int customHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
|
||||
MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
|
||||
final int customHeight = lp.height >= 0 ?
|
||||
Math.min(lp.height, height) : height;
|
||||
mCustomView.measure(MeasureSpec.makeMeasureSpec(customWidth, customWidthMode),
|
||||
MeasureSpec.makeMeasureSpec(customHeight, customHeightMode));
|
||||
}
|
||||
|
||||
if (mContentHeight <= 0) {
|
||||
int measuredHeight = 0;
|
||||
final int count = getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
View v = getChildAt(i);
|
||||
int paddedViewHeight = v.getMeasuredHeight() + verticalPadding;
|
||||
if (paddedViewHeight > measuredHeight) {
|
||||
measuredHeight = paddedViewHeight;
|
||||
}
|
||||
}
|
||||
setMeasuredDimension(contentWidth, measuredHeight);
|
||||
} else {
|
||||
setMeasuredDimension(contentWidth, maxHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private Animator makeInAnimation() {
|
||||
mClose.setTranslationX(-mClose.getWidth() -
|
||||
((MarginLayoutParams) mClose.getLayoutParams()).leftMargin);
|
||||
ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX", 0);
|
||||
buttonAnimator.setDuration(200);
|
||||
buttonAnimator.addListener(this);
|
||||
buttonAnimator.setInterpolator(new DecelerateInterpolator());
|
||||
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
AnimatorSet.Builder b = set.play(buttonAnimator);
|
||||
|
||||
if (mMenuView != null) {
|
||||
final int count = mMenuView.getChildCount();
|
||||
if (count > 0) {
|
||||
for (int i = count - 1, j = 0; i >= 0; i--, j++) {
|
||||
AnimatorProxy child = AnimatorProxy.wrap(mMenuView.getChildAt(i));
|
||||
child.setScaleY(0);
|
||||
ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0, 1);
|
||||
a.setDuration(100);
|
||||
a.setStartDelay(j * 70);
|
||||
b.with(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
private Animator makeOutAnimation() {
|
||||
ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX",
|
||||
-mClose.getWidth() - ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin);
|
||||
buttonAnimator.setDuration(200);
|
||||
buttonAnimator.addListener(this);
|
||||
buttonAnimator.setInterpolator(new DecelerateInterpolator());
|
||||
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
AnimatorSet.Builder b = set.play(buttonAnimator);
|
||||
|
||||
if (mMenuView != null) {
|
||||
final int count = mMenuView.getChildCount();
|
||||
if (count > 0) {
|
||||
for (int i = 0; i < 0; i++) {
|
||||
AnimatorProxy child = AnimatorProxy.wrap(mMenuView.getChildAt(i));
|
||||
child.setScaleY(0);
|
||||
ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0);
|
||||
a.setDuration(100);
|
||||
a.setStartDelay(i * 70);
|
||||
b.with(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
@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 (mClose != null && mClose.getVisibility() != GONE) {
|
||||
MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams();
|
||||
x += lp.leftMargin;
|
||||
x += positionChild(mClose, x, y, contentHeight);
|
||||
x += lp.rightMargin;
|
||||
|
||||
if (mAnimateInOnLayout) {
|
||||
mAnimationMode = ANIMATE_IN;
|
||||
mCurrentAnimation = makeInAnimation();
|
||||
mCurrentAnimation.start();
|
||||
mAnimateInOnLayout = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mTitleLayout != null && mCustomView == null) {
|
||||
x += positionChild(mTitleLayout, x, y, contentHeight);
|
||||
}
|
||||
|
||||
if (mCustomView != null) {
|
||||
x += positionChild(mCustomView, x, y, contentHeight);
|
||||
}
|
||||
|
||||
x = r - l - getPaddingRight();
|
||||
|
||||
if (mMenuView != null) {
|
||||
x -= positionChildInverse(mMenuView, x, y, contentHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mAnimationMode == ANIMATE_OUT) {
|
||||
killMode();
|
||||
}
|
||||
mAnimationMode = ANIMATE_IDLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDelayChildPressedState() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
|
||||
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
|
||||
// Action mode started
|
||||
//TODO event.setSource(this);
|
||||
event.setClassName(getClass().getName());
|
||||
event.setPackageName(getContext().getPackageName());
|
||||
event.setContentDescription(mTitle);
|
||||
} else {
|
||||
//TODO super.onInitializeAccessibilityEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import java.util.Locale;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.Button;
|
||||
|
||||
public class CapitalizingButton extends Button {
|
||||
private static final boolean SANS_ICE_CREAM = Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH;
|
||||
private static final boolean IS_GINGERBREAD = Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
|
||||
|
||||
private static final int[] R_styleable_Button = new int[] {
|
||||
android.R.attr.textAllCaps
|
||||
};
|
||||
private static final int R_styleable_Button_textAllCaps = 0;
|
||||
|
||||
private boolean mAllCaps;
|
||||
|
||||
public CapitalizingButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R_styleable_Button);
|
||||
mAllCaps = a.getBoolean(R_styleable_Button_textAllCaps, true);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public void setTextCompat(CharSequence text) {
|
||||
if (SANS_ICE_CREAM && mAllCaps && text != null) {
|
||||
if (IS_GINGERBREAD) {
|
||||
setText(text.toString().toUpperCase(Locale.ROOT));
|
||||
} else {
|
||||
setText(text.toString().toUpperCase());
|
||||
}
|
||||
} else {
|
||||
setText(text);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class CapitalizingTextView extends TextView {
|
||||
private static final boolean SANS_ICE_CREAM = Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH;
|
||||
private static final boolean IS_GINGERBREAD = Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
|
||||
|
||||
private static final int[] R_styleable_TextView = new int[] {
|
||||
android.R.attr.textAllCaps
|
||||
};
|
||||
private static final int R_styleable_TextView_textAllCaps = 0;
|
||||
|
||||
private boolean mAllCaps;
|
||||
|
||||
public CapitalizingTextView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public CapitalizingTextView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R_styleable_TextView, defStyle, 0);
|
||||
mAllCaps = a.getBoolean(R_styleable_TextView_textAllCaps, true);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public void setTextCompat(CharSequence text) {
|
||||
if (SANS_ICE_CREAM && mAllCaps && text != null) {
|
||||
if (IS_GINGERBREAD) {
|
||||
try {
|
||||
setText(text.toString().toUpperCase(Locale.ROOT));
|
||||
} catch (NoSuchFieldError e) {
|
||||
//Some manufacturer broke Locale.ROOT. See #572.
|
||||
setText(text.toString().toUpperCase());
|
||||
}
|
||||
} else {
|
||||
setText(text.toString().toUpperCase());
|
||||
}
|
||||
} else {
|
||||
setText(text);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import com.actionbarsherlock.view.CollapsibleActionView;
|
||||
|
||||
/**
|
||||
* Wraps an ABS collapsible action view in a native container that delegates the calls.
|
||||
*/
|
||||
public class CollapsibleActionViewWrapper extends FrameLayout implements android.view.CollapsibleActionView {
|
||||
private final CollapsibleActionView child;
|
||||
|
||||
public CollapsibleActionViewWrapper(View child) {
|
||||
super(child.getContext());
|
||||
this.child = (CollapsibleActionView) child;
|
||||
addView(child);
|
||||
}
|
||||
|
||||
@Override public void onActionViewExpanded() {
|
||||
child.onActionViewExpanded();
|
||||
}
|
||||
|
||||
@Override public void onActionViewCollapsed() {
|
||||
child.onActionViewCollapsed();
|
||||
}
|
||||
|
||||
public View unwrap() {
|
||||
return getChildAt(0);
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import static android.view.View.MeasureSpec.EXACTLY;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
import android.widget.LinearLayout;
|
||||
import com.actionbarsherlock.R;
|
||||
|
||||
public class FakeDialogPhoneWindow extends LinearLayout {
|
||||
final TypedValue mMinWidthMajor = new TypedValue();
|
||||
final TypedValue mMinWidthMinor = new TypedValue();
|
||||
|
||||
public FakeDialogPhoneWindow(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SherlockTheme);
|
||||
|
||||
a.getValue(R.styleable.SherlockTheme_windowMinWidthMajor, mMinWidthMajor);
|
||||
a.getValue(R.styleable.SherlockTheme_windowMinWidthMinor, mMinWidthMinor);
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
/* Stolen from PhoneWindow */
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
|
||||
final boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
|
||||
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
int width = getMeasuredWidth();
|
||||
boolean measure = false;
|
||||
|
||||
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY);
|
||||
|
||||
final TypedValue tv = isPortrait ? mMinWidthMinor : mMinWidthMajor;
|
||||
|
||||
if (tv.type != TypedValue.TYPE_NULL) {
|
||||
final int min;
|
||||
if (tv.type == TypedValue.TYPE_DIMENSION) {
|
||||
min = (int)tv.getDimension(metrics);
|
||||
} else if (tv.type == TypedValue.TYPE_FRACTION) {
|
||||
min = (int)tv.getFraction(metrics.widthPixels, metrics.widthPixels);
|
||||
} else {
|
||||
min = 0;
|
||||
}
|
||||
|
||||
if (width < min) {
|
||||
widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY);
|
||||
measure = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Support height?
|
||||
|
||||
if (measure) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,479 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.DataSetObserver;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.SpinnerAdapter;
|
||||
|
||||
/**
|
||||
* An abstract base class for spinner widgets. SDK users will probably not
|
||||
* need to use this class.
|
||||
*
|
||||
* @attr ref android.R.styleable#AbsSpinner_entries
|
||||
*/
|
||||
public abstract class IcsAbsSpinner extends IcsAdapterView<SpinnerAdapter> {
|
||||
private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
|
||||
|
||||
SpinnerAdapter mAdapter;
|
||||
|
||||
int mHeightMeasureSpec;
|
||||
int mWidthMeasureSpec;
|
||||
boolean mBlockLayoutRequests;
|
||||
|
||||
int mSelectionLeftPadding = 0;
|
||||
int mSelectionTopPadding = 0;
|
||||
int mSelectionRightPadding = 0;
|
||||
int mSelectionBottomPadding = 0;
|
||||
final Rect mSpinnerPadding = new Rect();
|
||||
|
||||
final RecycleBin mRecycler = new RecycleBin();
|
||||
private DataSetObserver mDataSetObserver;
|
||||
|
||||
/** Temporary frame to hold a child View's frame rectangle */
|
||||
private Rect mTouchFrame;
|
||||
|
||||
public IcsAbsSpinner(Context context) {
|
||||
super(context);
|
||||
initAbsSpinner();
|
||||
}
|
||||
|
||||
public IcsAbsSpinner(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public IcsAbsSpinner(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
initAbsSpinner();
|
||||
|
||||
/*
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
com.android.internal.R.styleable.AbsSpinner, defStyle, 0);
|
||||
|
||||
CharSequence[] entries = a.getTextArray(R.styleable.AbsSpinner_entries);
|
||||
if (entries != null) {
|
||||
ArrayAdapter<CharSequence> adapter =
|
||||
new ArrayAdapter<CharSequence>(context,
|
||||
R.layout.simple_spinner_item, entries);
|
||||
adapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
|
||||
setAdapter(adapter);
|
||||
}
|
||||
|
||||
a.recycle();
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Common code for different constructor flavors
|
||||
*/
|
||||
private void initAbsSpinner() {
|
||||
setFocusable(true);
|
||||
setWillNotDraw(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Adapter is used to provide the data which backs this Spinner.
|
||||
* It also provides methods to transform spinner items based on their position
|
||||
* relative to the selected item.
|
||||
* @param adapter The SpinnerAdapter to use for this Spinner
|
||||
*/
|
||||
@Override
|
||||
public void setAdapter(SpinnerAdapter adapter) {
|
||||
if (null != mAdapter) {
|
||||
mAdapter.unregisterDataSetObserver(mDataSetObserver);
|
||||
resetList();
|
||||
}
|
||||
|
||||
mAdapter = adapter;
|
||||
|
||||
mOldSelectedPosition = INVALID_POSITION;
|
||||
mOldSelectedRowId = INVALID_ROW_ID;
|
||||
|
||||
if (mAdapter != null) {
|
||||
mOldItemCount = mItemCount;
|
||||
mItemCount = mAdapter.getCount();
|
||||
checkFocus();
|
||||
|
||||
mDataSetObserver = new AdapterDataSetObserver();
|
||||
mAdapter.registerDataSetObserver(mDataSetObserver);
|
||||
|
||||
int position = mItemCount > 0 ? 0 : INVALID_POSITION;
|
||||
|
||||
setSelectedPositionInt(position);
|
||||
setNextSelectedPositionInt(position);
|
||||
|
||||
if (mItemCount == 0) {
|
||||
// Nothing selected
|
||||
checkSelectionChanged();
|
||||
}
|
||||
|
||||
} else {
|
||||
checkFocus();
|
||||
resetList();
|
||||
// Nothing selected
|
||||
checkSelectionChanged();
|
||||
}
|
||||
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear out all children from the list
|
||||
*/
|
||||
void resetList() {
|
||||
mDataChanged = false;
|
||||
mNeedSync = false;
|
||||
|
||||
removeAllViewsInLayout();
|
||||
mOldSelectedPosition = INVALID_POSITION;
|
||||
mOldSelectedRowId = INVALID_ROW_ID;
|
||||
|
||||
setSelectedPositionInt(INVALID_POSITION);
|
||||
setNextSelectedPositionInt(INVALID_POSITION);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see android.view.View#measure(int, int)
|
||||
*
|
||||
* Figure out the dimensions of this Spinner. The width comes from
|
||||
* the widthMeasureSpec as Spinnners can't have their width set to
|
||||
* UNSPECIFIED. The height is based on the height of the selected item
|
||||
* plus padding.
|
||||
*/
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
int widthSize;
|
||||
int heightSize;
|
||||
|
||||
final int mPaddingLeft = getPaddingLeft();
|
||||
final int mPaddingTop = getPaddingTop();
|
||||
final int mPaddingRight = getPaddingRight();
|
||||
final int mPaddingBottom = getPaddingBottom();
|
||||
|
||||
mSpinnerPadding.left = mPaddingLeft > mSelectionLeftPadding ? mPaddingLeft
|
||||
: mSelectionLeftPadding;
|
||||
mSpinnerPadding.top = mPaddingTop > mSelectionTopPadding ? mPaddingTop
|
||||
: mSelectionTopPadding;
|
||||
mSpinnerPadding.right = mPaddingRight > mSelectionRightPadding ? mPaddingRight
|
||||
: mSelectionRightPadding;
|
||||
mSpinnerPadding.bottom = mPaddingBottom > mSelectionBottomPadding ? mPaddingBottom
|
||||
: mSelectionBottomPadding;
|
||||
|
||||
if (mDataChanged) {
|
||||
handleDataChanged();
|
||||
}
|
||||
|
||||
int preferredHeight = 0;
|
||||
int preferredWidth = 0;
|
||||
boolean needsMeasuring = true;
|
||||
|
||||
int selectedPosition = getSelectedItemPosition();
|
||||
if (selectedPosition >= 0 && mAdapter != null && selectedPosition < mAdapter.getCount()) {
|
||||
// Try looking in the recycler. (Maybe we were measured once already)
|
||||
View view = mRecycler.get(selectedPosition);
|
||||
if (view == null) {
|
||||
// Make a new one
|
||||
view = mAdapter.getView(selectedPosition, null, this);
|
||||
}
|
||||
|
||||
if (view != null) {
|
||||
// Put in recycler for re-measuring and/or layout
|
||||
mRecycler.put(selectedPosition, view);
|
||||
}
|
||||
|
||||
if (view != null) {
|
||||
if (view.getLayoutParams() == null) {
|
||||
mBlockLayoutRequests = true;
|
||||
view.setLayoutParams(generateDefaultLayoutParams());
|
||||
mBlockLayoutRequests = false;
|
||||
}
|
||||
measureChild(view, widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
preferredHeight = getChildHeight(view) + mSpinnerPadding.top + mSpinnerPadding.bottom;
|
||||
preferredWidth = getChildWidth(view) + mSpinnerPadding.left + mSpinnerPadding.right;
|
||||
|
||||
needsMeasuring = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsMeasuring) {
|
||||
// No views -- just use padding
|
||||
preferredHeight = mSpinnerPadding.top + mSpinnerPadding.bottom;
|
||||
if (widthMode == MeasureSpec.UNSPECIFIED) {
|
||||
preferredWidth = mSpinnerPadding.left + mSpinnerPadding.right;
|
||||
}
|
||||
}
|
||||
|
||||
preferredHeight = Math.max(preferredHeight, getSuggestedMinimumHeight());
|
||||
preferredWidth = Math.max(preferredWidth, getSuggestedMinimumWidth());
|
||||
|
||||
if (IS_HONEYCOMB) {
|
||||
heightSize = resolveSizeAndState(preferredHeight, heightMeasureSpec, 0);
|
||||
widthSize = resolveSizeAndState(preferredWidth, widthMeasureSpec, 0);
|
||||
} else {
|
||||
heightSize = resolveSize(preferredHeight, heightMeasureSpec);
|
||||
widthSize = resolveSize(preferredWidth, widthMeasureSpec);
|
||||
}
|
||||
|
||||
setMeasuredDimension(widthSize, heightSize);
|
||||
mHeightMeasureSpec = heightMeasureSpec;
|
||||
mWidthMeasureSpec = widthMeasureSpec;
|
||||
}
|
||||
|
||||
int getChildHeight(View child) {
|
||||
return child.getMeasuredHeight();
|
||||
}
|
||||
|
||||
int getChildWidth(View child) {
|
||||
return child.getMeasuredWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
|
||||
return new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
|
||||
void recycleAllViews() {
|
||||
final int childCount = getChildCount();
|
||||
final IcsAbsSpinner.RecycleBin recycleBin = mRecycler;
|
||||
final int position = mFirstPosition;
|
||||
|
||||
// All views go in recycler
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
View v = getChildAt(i);
|
||||
int index = position + i;
|
||||
recycleBin.put(index, v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Jump directly to a specific item in the adapter data.
|
||||
*/
|
||||
public void setSelection(int position, boolean animate) {
|
||||
// Animate only if requested position is already on screen somewhere
|
||||
boolean shouldAnimate = animate && mFirstPosition <= position &&
|
||||
position <= mFirstPosition + getChildCount() - 1;
|
||||
setSelectionInt(position, shouldAnimate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelection(int position) {
|
||||
setNextSelectedPositionInt(position);
|
||||
requestLayout();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Makes the item at the supplied position selected.
|
||||
*
|
||||
* @param position Position to select
|
||||
* @param animate Should the transition be animated
|
||||
*
|
||||
*/
|
||||
void setSelectionInt(int position, boolean animate) {
|
||||
if (position != mOldSelectedPosition) {
|
||||
mBlockLayoutRequests = true;
|
||||
int delta = position - mSelectedPosition;
|
||||
setNextSelectedPositionInt(position);
|
||||
layout(delta, animate);
|
||||
mBlockLayoutRequests = false;
|
||||
}
|
||||
}
|
||||
|
||||
abstract void layout(int delta, boolean animate);
|
||||
|
||||
@Override
|
||||
public View getSelectedView() {
|
||||
if (mItemCount > 0 && mSelectedPosition >= 0) {
|
||||
return getChildAt(mSelectedPosition - mFirstPosition);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to prevent spamming ourselves with layout requests
|
||||
* as we place views
|
||||
*
|
||||
* @see android.view.View#requestLayout()
|
||||
*/
|
||||
@Override
|
||||
public void requestLayout() {
|
||||
if (!mBlockLayoutRequests) {
|
||||
super.requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpinnerAdapter getAdapter() {
|
||||
return mAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mItemCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a point to a position in the list.
|
||||
*
|
||||
* @param x X in local coordinate
|
||||
* @param y Y in local coordinate
|
||||
* @return The position of the item which contains the specified point, or
|
||||
* {@link #INVALID_POSITION} if the point does not intersect an item.
|
||||
*/
|
||||
public int pointToPosition(int x, int y) {
|
||||
Rect frame = mTouchFrame;
|
||||
if (frame == null) {
|
||||
mTouchFrame = new Rect();
|
||||
frame = mTouchFrame;
|
||||
}
|
||||
|
||||
final int count = getChildCount();
|
||||
for (int i = count - 1; i >= 0; i--) {
|
||||
View child = getChildAt(i);
|
||||
if (child.getVisibility() == View.VISIBLE) {
|
||||
child.getHitRect(frame);
|
||||
if (frame.contains(x, y)) {
|
||||
return mFirstPosition + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return INVALID_POSITION;
|
||||
}
|
||||
|
||||
static class SavedState extends BaseSavedState {
|
||||
long selectedId;
|
||||
int position;
|
||||
|
||||
/**
|
||||
* Constructor called from {@link AbsSpinner#onSaveInstanceState()}
|
||||
*/
|
||||
SavedState(Parcelable superState) {
|
||||
super(superState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor called from {@link #CREATOR}
|
||||
*/
|
||||
private SavedState(Parcel in) {
|
||||
super(in);
|
||||
selectedId = in.readLong();
|
||||
position = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
super.writeToParcel(out, flags);
|
||||
out.writeLong(selectedId);
|
||||
out.writeInt(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AbsSpinner.SavedState{"
|
||||
+ Integer.toHexString(System.identityHashCode(this))
|
||||
+ " selectedId=" + selectedId
|
||||
+ " position=" + position + "}";
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<SavedState> CREATOR
|
||||
= new Parcelable.Creator<SavedState>() {
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
Parcelable superState = super.onSaveInstanceState();
|
||||
SavedState ss = new SavedState(superState);
|
||||
ss.selectedId = getSelectedItemId();
|
||||
if (ss.selectedId >= 0) {
|
||||
ss.position = getSelectedItemPosition();
|
||||
} else {
|
||||
ss.position = INVALID_POSITION;
|
||||
}
|
||||
return ss;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
SavedState ss = (SavedState) state;
|
||||
|
||||
super.onRestoreInstanceState(ss.getSuperState());
|
||||
|
||||
if (ss.selectedId >= 0) {
|
||||
mDataChanged = true;
|
||||
mNeedSync = true;
|
||||
mSyncRowId = ss.selectedId;
|
||||
mSyncPosition = ss.position;
|
||||
mSyncMode = SYNC_SELECTED_POSITION;
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
class RecycleBin {
|
||||
private final SparseArray<View> mScrapHeap = new SparseArray<View>();
|
||||
|
||||
public void put(int position, View v) {
|
||||
mScrapHeap.put(position, v);
|
||||
}
|
||||
|
||||
View get(int position) {
|
||||
// System.out.print("Looking for " + position);
|
||||
View result = mScrapHeap.get(position);
|
||||
if (result != null) {
|
||||
// System.out.println(" HIT");
|
||||
mScrapHeap.delete(position);
|
||||
} else {
|
||||
// System.out.println(" MISS");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
final SparseArray<View> scrapHeap = mScrapHeap;
|
||||
final int count = scrapHeap.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View view = scrapHeap.valueAt(i);
|
||||
if (view != null) {
|
||||
removeDetachedView(view, true);
|
||||
}
|
||||
}
|
||||
scrapHeap.clear();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
/**
|
||||
* A version of {@link android.graphics.drawable.ColorDrawable} that respects bounds.
|
||||
*/
|
||||
public class IcsColorDrawable extends Drawable {
|
||||
private int color;
|
||||
private final Paint paint = new Paint();
|
||||
|
||||
public IcsColorDrawable(int color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override public void draw(Canvas canvas) {
|
||||
if ((color >>> 24) != 0) {
|
||||
paint.setColor(color);
|
||||
canvas.drawRect(getBounds(), paint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
if (alpha != (color >>> 24)) {
|
||||
color = (color & 0x00FFFFFF) & (alpha << 24);
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void setColorFilter(ColorFilter colorFilter) {
|
||||
//Ignored
|
||||
}
|
||||
|
||||
@Override public int getOpacity() {
|
||||
return color >>> 24;
|
||||
}
|
||||
}
|
@ -1,410 +0,0 @@
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout;
|
||||
|
||||
/**
|
||||
* A simple extension of a regular linear layout that supports the divider API
|
||||
* of Android 4.0+. The dividers are added adjacent to the children by changing
|
||||
* their layout params. If you need to rely on the margins which fall in the
|
||||
* same orientation as the layout you should wrap the child in a simple
|
||||
* {@link android.widget.FrameLayout} so it can receive the margin.
|
||||
*/
|
||||
public class IcsLinearLayout extends NineLinearLayout {
|
||||
private static final int[] R_styleable_LinearLayout = new int[] {
|
||||
/* 0 */ android.R.attr.divider,
|
||||
/* 1 */ android.R.attr.measureWithLargestChild,
|
||||
/* 2 */ android.R.attr.showDividers,
|
||||
/* 3 */ android.R.attr.dividerPadding,
|
||||
};
|
||||
private static final int LinearLayout_divider = 0;
|
||||
private static final int LinearLayout_measureWithLargestChild = 1;
|
||||
private static final int LinearLayout_showDividers = 2;
|
||||
private static final int LinearLayout_dividerPadding = 3;
|
||||
|
||||
/**
|
||||
* Don't show any dividers.
|
||||
*/
|
||||
public static final int SHOW_DIVIDER_NONE = 0;
|
||||
/**
|
||||
* Show a divider at the beginning of the group.
|
||||
*/
|
||||
public static final int SHOW_DIVIDER_BEGINNING = 1;
|
||||
/**
|
||||
* Show dividers between each item in the group.
|
||||
*/
|
||||
public static final int SHOW_DIVIDER_MIDDLE = 2;
|
||||
/**
|
||||
* Show a divider at the end of the group.
|
||||
*/
|
||||
public static final int SHOW_DIVIDER_END = 4;
|
||||
|
||||
|
||||
private Drawable mDivider;
|
||||
private int mDividerWidth;
|
||||
private int mDividerHeight;
|
||||
private int mShowDividers;
|
||||
private int mDividerPadding;
|
||||
|
||||
private boolean mUseLargestChild;
|
||||
|
||||
public IcsLinearLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, /*com.android.internal.R.styleable.*/R_styleable_LinearLayout);
|
||||
|
||||
setDividerDrawable(a.getDrawable(/*com.android.internal.R.styleable.*/LinearLayout_divider));
|
||||
mShowDividers = a.getInt(/*com.android.internal.R.styleable.*/LinearLayout_showDividers, SHOW_DIVIDER_NONE);
|
||||
mDividerPadding = a.getDimensionPixelSize(/*com.android.internal.R.styleable.*/LinearLayout_dividerPadding, 0);
|
||||
mUseLargestChild = a.getBoolean(/*com.android.internal.R.styleable.*/LinearLayout_measureWithLargestChild, false);
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set how dividers should be shown between items in this layout
|
||||
*
|
||||
* @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING},
|
||||
* {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END},
|
||||
* or {@link #SHOW_DIVIDER_NONE} to show no dividers.
|
||||
*/
|
||||
public void setShowDividers(int showDividers) {
|
||||
if (showDividers != mShowDividers) {
|
||||
requestLayout();
|
||||
invalidate(); //XXX This is required if you are toggling a divider off
|
||||
}
|
||||
mShowDividers = showDividers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A flag set indicating how dividers should be shown around items.
|
||||
* @see #setShowDividers(int)
|
||||
*/
|
||||
public int getShowDividers() {
|
||||
return mShowDividers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a drawable to be used as a divider between items.
|
||||
* @param divider Drawable that will divide each item.
|
||||
* @see #setShowDividers(int)
|
||||
*/
|
||||
public void setDividerDrawable(Drawable divider) {
|
||||
if (divider == mDivider) {
|
||||
return;
|
||||
}
|
||||
mDivider = divider;
|
||||
if (divider != null) {
|
||||
mDividerWidth = divider.getIntrinsicWidth();
|
||||
mDividerHeight = divider.getIntrinsicHeight();
|
||||
} else {
|
||||
mDividerWidth = 0;
|
||||
mDividerHeight = 0;
|
||||
}
|
||||
setWillNotDraw(divider == null);
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set padding displayed on both ends of dividers.
|
||||
*
|
||||
* @param padding Padding value in pixels that will be applied to each end
|
||||
*
|
||||
* @see #setShowDividers(int)
|
||||
* @see #setDividerDrawable(Drawable)
|
||||
* @see #getDividerPadding()
|
||||
*/
|
||||
public void setDividerPadding(int padding) {
|
||||
mDividerPadding = padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the padding size used to inset dividers in pixels
|
||||
*
|
||||
* @see #setShowDividers(int)
|
||||
* @see #setDividerDrawable(Drawable)
|
||||
* @see #setDividerPadding(int)
|
||||
*/
|
||||
public int getDividerPadding() {
|
||||
return mDividerPadding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of the current divider drawable.
|
||||
*
|
||||
* @hide Used internally by framework.
|
||||
*/
|
||||
public int getDividerWidth() {
|
||||
return mDividerWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
|
||||
final int index = indexOfChild(child);
|
||||
final int orientation = getOrientation();
|
||||
final LayoutParams params = (LayoutParams) child.getLayoutParams();
|
||||
if (hasDividerBeforeChildAt(index)) {
|
||||
if (orientation == VERTICAL) {
|
||||
//Account for the divider by pushing everything up
|
||||
params.topMargin = mDividerHeight;
|
||||
} else {
|
||||
//Account for the divider by pushing everything left
|
||||
params.leftMargin = mDividerWidth;
|
||||
}
|
||||
}
|
||||
|
||||
final int count = getChildCount();
|
||||
if (index == count - 1) {
|
||||
if (hasDividerBeforeChildAt(count)) {
|
||||
if (orientation == VERTICAL) {
|
||||
params.bottomMargin = mDividerHeight;
|
||||
} else {
|
||||
params.rightMargin = mDividerWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (mDivider != null) {
|
||||
if (getOrientation() == VERTICAL) {
|
||||
drawDividersVertical(canvas);
|
||||
} else {
|
||||
drawDividersHorizontal(canvas);
|
||||
}
|
||||
}
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
|
||||
void drawDividersVertical(Canvas canvas) {
|
||||
final int count = getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
|
||||
if (child != null && child.getVisibility() != GONE) {
|
||||
if (hasDividerBeforeChildAt(i)) {
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
final int top = child.getTop() - lp.topMargin/* - mDividerHeight*/;
|
||||
drawHorizontalDivider(canvas, top);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDividerBeforeChildAt(count)) {
|
||||
final View child = getChildAt(count - 1);
|
||||
int bottom = 0;
|
||||
if (child == null) {
|
||||
bottom = getHeight() - getPaddingBottom() - mDividerHeight;
|
||||
} else {
|
||||
//final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
bottom = child.getBottom()/* + lp.bottomMargin*/;
|
||||
}
|
||||
drawHorizontalDivider(canvas, bottom);
|
||||
}
|
||||
}
|
||||
|
||||
void drawDividersHorizontal(Canvas canvas) {
|
||||
final int count = getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
|
||||
if (child != null && child.getVisibility() != GONE) {
|
||||
if (hasDividerBeforeChildAt(i)) {
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
final int left = child.getLeft() - lp.leftMargin/* - mDividerWidth*/;
|
||||
drawVerticalDivider(canvas, left);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDividerBeforeChildAt(count)) {
|
||||
final View child = getChildAt(count - 1);
|
||||
int right = 0;
|
||||
if (child == null) {
|
||||
right = getWidth() - getPaddingRight() - mDividerWidth;
|
||||
} else {
|
||||
//final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
right = child.getRight()/* + lp.rightMargin*/;
|
||||
}
|
||||
drawVerticalDivider(canvas, right);
|
||||
}
|
||||
}
|
||||
|
||||
void drawHorizontalDivider(Canvas canvas, int top) {
|
||||
mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
|
||||
getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
|
||||
mDivider.draw(canvas);
|
||||
}
|
||||
|
||||
void drawVerticalDivider(Canvas canvas, int left) {
|
||||
mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
|
||||
left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
|
||||
mDivider.draw(canvas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines where to position dividers between children.
|
||||
*
|
||||
* @param childIndex Index of child to check for preceding divider
|
||||
* @return true if there should be a divider before the child at childIndex
|
||||
* @hide Pending API consideration. Currently only used internally by the system.
|
||||
*/
|
||||
protected boolean hasDividerBeforeChildAt(int childIndex) {
|
||||
if (childIndex == 0) {
|
||||
return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
|
||||
} else if (childIndex == getChildCount()) {
|
||||
return (mShowDividers & SHOW_DIVIDER_END) != 0;
|
||||
} else if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {
|
||||
boolean hasVisibleViewBefore = false;
|
||||
for (int i = childIndex - 1; i >= 0; i--) {
|
||||
if (getChildAt(i).getVisibility() != GONE) {
|
||||
hasVisibleViewBefore = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hasVisibleViewBefore;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* When true, all children with a weight will be considered having
|
||||
* the minimum size of the largest child. If false, all children are
|
||||
* measured normally.
|
||||
*
|
||||
* @return True to measure children with a weight using the minimum
|
||||
* size of the largest child, false otherwise.
|
||||
*
|
||||
* @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
|
||||
*/
|
||||
public boolean isMeasureWithLargestChildEnabled() {
|
||||
return mUseLargestChild;
|
||||
}
|
||||
|
||||
/**
|
||||
* When set to true, all children with a weight will be considered having
|
||||
* the minimum size of the largest child. If false, all children are
|
||||
* measured normally.
|
||||
*
|
||||
* Disabled by default.
|
||||
*
|
||||
* @param enabled True to measure children with a weight using the
|
||||
* minimum size of the largest child, false otherwise.
|
||||
*
|
||||
* @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
|
||||
*/
|
||||
public void setMeasureWithLargestChildEnabled(boolean enabled) {
|
||||
mUseLargestChild = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
if (mUseLargestChild) {
|
||||
final int orientation = getOrientation();
|
||||
switch (orientation) {
|
||||
case HORIZONTAL:
|
||||
useLargestChildHorizontal();
|
||||
break;
|
||||
|
||||
case VERTICAL:
|
||||
useLargestChildVertical();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void useLargestChildHorizontal() {
|
||||
final int childCount = getChildCount();
|
||||
|
||||
// Find largest child width
|
||||
int largestChildWidth = 0;
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
largestChildWidth = Math.max(child.getMeasuredWidth(), largestChildWidth);
|
||||
}
|
||||
|
||||
int totalWidth = 0;
|
||||
// Re-measure childs
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
|
||||
if (child == null || child.getVisibility() == View.GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final LinearLayout.LayoutParams lp =
|
||||
(LinearLayout.LayoutParams) child.getLayoutParams();
|
||||
|
||||
float childExtra = lp.weight;
|
||||
if (childExtra > 0) {
|
||||
child.measure(
|
||||
MeasureSpec.makeMeasureSpec(largestChildWidth,
|
||||
MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(),
|
||||
MeasureSpec.EXACTLY));
|
||||
totalWidth += largestChildWidth;
|
||||
|
||||
} else {
|
||||
totalWidth += child.getMeasuredWidth();
|
||||
}
|
||||
|
||||
totalWidth += lp.leftMargin + lp.rightMargin;
|
||||
}
|
||||
|
||||
totalWidth += getPaddingLeft() + getPaddingRight();
|
||||
setMeasuredDimension(totalWidth, getMeasuredHeight());
|
||||
}
|
||||
|
||||
private void useLargestChildVertical() {
|
||||
final int childCount = getChildCount();
|
||||
|
||||
// Find largest child width
|
||||
int largestChildHeight = 0;
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
largestChildHeight = Math.max(child.getMeasuredHeight(), largestChildHeight);
|
||||
}
|
||||
|
||||
int totalHeight = 0;
|
||||
// Re-measure childs
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
|
||||
if (child == null || child.getVisibility() == View.GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final LinearLayout.LayoutParams lp =
|
||||
(LinearLayout.LayoutParams) child.getLayoutParams();
|
||||
|
||||
float childExtra = lp.weight;
|
||||
if (childExtra > 0) {
|
||||
child.measure(
|
||||
MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),
|
||||
MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(largestChildHeight,
|
||||
MeasureSpec.EXACTLY));
|
||||
totalHeight += largestChildHeight;
|
||||
|
||||
} else {
|
||||
totalHeight += child.getMeasuredHeight();
|
||||
}
|
||||
|
||||
totalHeight += lp.leftMargin + lp.rightMargin;
|
||||
}
|
||||
|
||||
totalHeight += getPaddingLeft() + getPaddingRight();
|
||||
setMeasuredDimension(getMeasuredWidth(), totalHeight);
|
||||
}
|
||||
}
|
@ -1,644 +0,0 @@
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.DataSetObserver;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.view.View.OnTouchListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.PopupWindow;
|
||||
|
||||
/**
|
||||
* A proxy between pre- and post-Honeycomb implementations of this class.
|
||||
*/
|
||||
public class IcsListPopupWindow {
|
||||
/**
|
||||
* This value controls the length of time that the user
|
||||
* must leave a pointer down without scrolling to expand
|
||||
* the autocomplete dropdown list to cover the IME.
|
||||
*/
|
||||
private static final int EXPAND_LIST_TIMEOUT = 250;
|
||||
|
||||
private Context mContext;
|
||||
private PopupWindow mPopup;
|
||||
private ListAdapter mAdapter;
|
||||
private DropDownListView mDropDownList;
|
||||
|
||||
private int mDropDownHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
private int mDropDownWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
private int mDropDownHorizontalOffset;
|
||||
private int mDropDownVerticalOffset;
|
||||
private boolean mDropDownVerticalOffsetSet;
|
||||
|
||||
private int mListItemExpandMaximum = Integer.MAX_VALUE;
|
||||
|
||||
private View mPromptView;
|
||||
private int mPromptPosition = POSITION_PROMPT_ABOVE;
|
||||
|
||||
private DataSetObserver mObserver;
|
||||
|
||||
private View mDropDownAnchorView;
|
||||
|
||||
private Drawable mDropDownListHighlight;
|
||||
|
||||
private AdapterView.OnItemClickListener mItemClickListener;
|
||||
private AdapterView.OnItemSelectedListener mItemSelectedListener;
|
||||
|
||||
private final ResizePopupRunnable mResizePopupRunnable = new ResizePopupRunnable();
|
||||
private final PopupTouchInterceptor mTouchInterceptor = new PopupTouchInterceptor();
|
||||
private final PopupScrollListener mScrollListener = new PopupScrollListener();
|
||||
private final ListSelectorHider mHideSelector = new ListSelectorHider();
|
||||
|
||||
private Handler mHandler = new Handler();
|
||||
|
||||
private Rect mTempRect = new Rect();
|
||||
|
||||
private boolean mModal;
|
||||
|
||||
public static final int POSITION_PROMPT_ABOVE = 0;
|
||||
public static final int POSITION_PROMPT_BELOW = 1;
|
||||
|
||||
public IcsListPopupWindow(Context context) {
|
||||
this(context, null, R.attr.listPopupWindowStyle);
|
||||
}
|
||||
|
||||
public IcsListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
mContext = context;
|
||||
mPopup = new PopupWindow(context, attrs, defStyleAttr);
|
||||
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
|
||||
}
|
||||
|
||||
public IcsListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
mContext = context;
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||||
Context wrapped = new ContextThemeWrapper(context, defStyleRes);
|
||||
mPopup = new PopupWindow(wrapped, attrs, defStyleAttr);
|
||||
} else {
|
||||
mPopup = new PopupWindow(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
|
||||
}
|
||||
|
||||
public void setAdapter(ListAdapter adapter) {
|
||||
if (mObserver == null) {
|
||||
mObserver = new PopupDataSetObserver();
|
||||
} else if (mAdapter != null) {
|
||||
mAdapter.unregisterDataSetObserver(mObserver);
|
||||
}
|
||||
mAdapter = adapter;
|
||||
if (mAdapter != null) {
|
||||
adapter.registerDataSetObserver(mObserver);
|
||||
}
|
||||
|
||||
if (mDropDownList != null) {
|
||||
mDropDownList.setAdapter(mAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPromptPosition(int position) {
|
||||
mPromptPosition = position;
|
||||
}
|
||||
|
||||
public void setModal(boolean modal) {
|
||||
mModal = true;
|
||||
mPopup.setFocusable(modal);
|
||||
}
|
||||
|
||||
public void setBackgroundDrawable(Drawable d) {
|
||||
mPopup.setBackgroundDrawable(d);
|
||||
}
|
||||
|
||||
public void setAnchorView(View anchor) {
|
||||
mDropDownAnchorView = anchor;
|
||||
}
|
||||
|
||||
public void setHorizontalOffset(int offset) {
|
||||
mDropDownHorizontalOffset = offset;
|
||||
}
|
||||
|
||||
public void setVerticalOffset(int offset) {
|
||||
mDropDownVerticalOffset = offset;
|
||||
mDropDownVerticalOffsetSet = true;
|
||||
}
|
||||
|
||||
public void setContentWidth(int width) {
|
||||
Drawable popupBackground = mPopup.getBackground();
|
||||
if (popupBackground != null) {
|
||||
popupBackground.getPadding(mTempRect);
|
||||
mDropDownWidth = mTempRect.left + mTempRect.right + width;
|
||||
} else {
|
||||
mDropDownWidth = width;
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnItemClickListener(AdapterView.OnItemClickListener clickListener) {
|
||||
mItemClickListener = clickListener;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
int height = buildDropDown();
|
||||
|
||||
int widthSpec = 0;
|
||||
int heightSpec = 0;
|
||||
|
||||
boolean noInputMethod = isInputMethodNotNeeded();
|
||||
//XXX mPopup.setAllowScrollingAnchorParent(!noInputMethod);
|
||||
|
||||
if (mPopup.isShowing()) {
|
||||
if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
|
||||
// The call to PopupWindow's update method below can accept -1 for any
|
||||
// value you do not want to update.
|
||||
widthSpec = -1;
|
||||
} else if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
|
||||
widthSpec = mDropDownAnchorView.getWidth();
|
||||
} else {
|
||||
widthSpec = mDropDownWidth;
|
||||
}
|
||||
|
||||
if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
|
||||
// The call to PopupWindow's update method below can accept -1 for any
|
||||
// value you do not want to update.
|
||||
heightSpec = noInputMethod ? height : ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
if (noInputMethod) {
|
||||
mPopup.setWindowLayoutMode(
|
||||
mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
|
||||
ViewGroup.LayoutParams.MATCH_PARENT : 0, 0);
|
||||
} else {
|
||||
mPopup.setWindowLayoutMode(
|
||||
mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
|
||||
ViewGroup.LayoutParams.MATCH_PARENT : 0,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
}
|
||||
} else if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
|
||||
heightSpec = height;
|
||||
} else {
|
||||
heightSpec = mDropDownHeight;
|
||||
}
|
||||
|
||||
mPopup.setOutsideTouchable(true);
|
||||
|
||||
mPopup.update(mDropDownAnchorView, mDropDownHorizontalOffset,
|
||||
mDropDownVerticalOffset, widthSpec, heightSpec);
|
||||
} else {
|
||||
if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
|
||||
widthSpec = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
} else {
|
||||
if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
|
||||
mPopup.setWidth(mDropDownAnchorView.getWidth());
|
||||
} else {
|
||||
mPopup.setWidth(mDropDownWidth);
|
||||
}
|
||||
}
|
||||
|
||||
if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
|
||||
heightSpec = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
} else {
|
||||
if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
|
||||
mPopup.setHeight(height);
|
||||
} else {
|
||||
mPopup.setHeight(mDropDownHeight);
|
||||
}
|
||||
}
|
||||
|
||||
mPopup.setWindowLayoutMode(widthSpec, heightSpec);
|
||||
//XXX mPopup.setClipToScreenEnabled(true);
|
||||
|
||||
// use outside touchable to dismiss drop down when touching outside of it, so
|
||||
// only set this if the dropdown is not always visible
|
||||
mPopup.setOutsideTouchable(true);
|
||||
mPopup.setTouchInterceptor(mTouchInterceptor);
|
||||
mPopup.showAsDropDown(mDropDownAnchorView,
|
||||
mDropDownHorizontalOffset, mDropDownVerticalOffset);
|
||||
mDropDownList.setSelection(ListView.INVALID_POSITION);
|
||||
|
||||
if (!mModal || mDropDownList.isInTouchMode()) {
|
||||
clearListSelection();
|
||||
}
|
||||
if (!mModal) {
|
||||
mHandler.post(mHideSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
mPopup.dismiss();
|
||||
if (mPromptView != null) {
|
||||
final ViewParent parent = mPromptView.getParent();
|
||||
if (parent instanceof ViewGroup) {
|
||||
final ViewGroup group = (ViewGroup) parent;
|
||||
group.removeView(mPromptView);
|
||||
}
|
||||
}
|
||||
mPopup.setContentView(null);
|
||||
mDropDownList = null;
|
||||
mHandler.removeCallbacks(mResizePopupRunnable);
|
||||
}
|
||||
|
||||
public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
|
||||
mPopup.setOnDismissListener(listener);
|
||||
}
|
||||
|
||||
public void setInputMethodMode(int mode) {
|
||||
mPopup.setInputMethodMode(mode);
|
||||
}
|
||||
|
||||
public void clearListSelection() {
|
||||
final DropDownListView list = mDropDownList;
|
||||
if (list != null) {
|
||||
// WARNING: Please read the comment where mListSelectionHidden is declared
|
||||
list.mListSelectionHidden = true;
|
||||
//XXX list.hideSelector();
|
||||
list.requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isShowing() {
|
||||
return mPopup.isShowing();
|
||||
}
|
||||
|
||||
private boolean isInputMethodNotNeeded() {
|
||||
return mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
|
||||
}
|
||||
|
||||
public ListView getListView() {
|
||||
return mDropDownList;
|
||||
}
|
||||
|
||||
private int buildDropDown() {
|
||||
ViewGroup dropDownView;
|
||||
int otherHeights = 0;
|
||||
|
||||
if (mDropDownList == null) {
|
||||
Context context = mContext;
|
||||
|
||||
mDropDownList = new DropDownListView(context, !mModal);
|
||||
if (mDropDownListHighlight != null) {
|
||||
mDropDownList.setSelector(mDropDownListHighlight);
|
||||
}
|
||||
mDropDownList.setAdapter(mAdapter);
|
||||
mDropDownList.setOnItemClickListener(mItemClickListener);
|
||||
mDropDownList.setFocusable(true);
|
||||
mDropDownList.setFocusableInTouchMode(true);
|
||||
mDropDownList.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
public void onItemSelected(AdapterView<?> parent, View view,
|
||||
int position, long id) {
|
||||
|
||||
if (position != -1) {
|
||||
DropDownListView dropDownList = mDropDownList;
|
||||
|
||||
if (dropDownList != null) {
|
||||
dropDownList.mListSelectionHidden = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
mDropDownList.setOnScrollListener(mScrollListener);
|
||||
|
||||
if (mItemSelectedListener != null) {
|
||||
mDropDownList.setOnItemSelectedListener(mItemSelectedListener);
|
||||
}
|
||||
|
||||
dropDownView = mDropDownList;
|
||||
|
||||
View hintView = mPromptView;
|
||||
if (hintView != null) {
|
||||
// if an hint has been specified, we accomodate more space for it and
|
||||
// add a text view in the drop down menu, at the bottom of the list
|
||||
LinearLayout hintContainer = new LinearLayout(context);
|
||||
hintContainer.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
LinearLayout.LayoutParams hintParams = new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, 0, 1.0f
|
||||
);
|
||||
|
||||
switch (mPromptPosition) {
|
||||
case POSITION_PROMPT_BELOW:
|
||||
hintContainer.addView(dropDownView, hintParams);
|
||||
hintContainer.addView(hintView);
|
||||
break;
|
||||
|
||||
case POSITION_PROMPT_ABOVE:
|
||||
hintContainer.addView(hintView);
|
||||
hintContainer.addView(dropDownView, hintParams);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// measure the hint's height to find how much more vertical space
|
||||
// we need to add to the drop down's height
|
||||
int widthSpec = MeasureSpec.makeMeasureSpec(mDropDownWidth, MeasureSpec.AT_MOST);
|
||||
int heightSpec = MeasureSpec.UNSPECIFIED;
|
||||
hintView.measure(widthSpec, heightSpec);
|
||||
|
||||
hintParams = (LinearLayout.LayoutParams) hintView.getLayoutParams();
|
||||
otherHeights = hintView.getMeasuredHeight() + hintParams.topMargin
|
||||
+ hintParams.bottomMargin;
|
||||
|
||||
dropDownView = hintContainer;
|
||||
}
|
||||
|
||||
mPopup.setContentView(dropDownView);
|
||||
} else {
|
||||
dropDownView = (ViewGroup) mPopup.getContentView();
|
||||
final View view = mPromptView;
|
||||
if (view != null) {
|
||||
LinearLayout.LayoutParams hintParams =
|
||||
(LinearLayout.LayoutParams) view.getLayoutParams();
|
||||
otherHeights = view.getMeasuredHeight() + hintParams.topMargin
|
||||
+ hintParams.bottomMargin;
|
||||
}
|
||||
}
|
||||
|
||||
// getMaxAvailableHeight() subtracts the padding, so we put it back
|
||||
// to get the available height for the whole window
|
||||
int padding = 0;
|
||||
Drawable background = mPopup.getBackground();
|
||||
if (background != null) {
|
||||
background.getPadding(mTempRect);
|
||||
padding = mTempRect.top + mTempRect.bottom;
|
||||
|
||||
// If we don't have an explicit vertical offset, determine one from the window
|
||||
// background so that content will line up.
|
||||
if (!mDropDownVerticalOffsetSet) {
|
||||
mDropDownVerticalOffset = -mTempRect.top;
|
||||
}
|
||||
}
|
||||
|
||||
// Max height available on the screen for a popup.
|
||||
boolean ignoreBottomDecorations =
|
||||
mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
|
||||
final int maxHeight = /*mPopup.*/getMaxAvailableHeight(
|
||||
mDropDownAnchorView, mDropDownVerticalOffset, ignoreBottomDecorations);
|
||||
|
||||
if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
|
||||
return maxHeight + padding;
|
||||
}
|
||||
|
||||
final int listContent = /*mDropDownList.*/measureHeightOfChildren(MeasureSpec.UNSPECIFIED,
|
||||
0, -1/*ListView.NO_POSITION*/, maxHeight - otherHeights, -1);
|
||||
// add padding only if the list has items in it, that way we don't show
|
||||
// the popup if it is not needed
|
||||
if (listContent > 0) otherHeights += padding;
|
||||
|
||||
return listContent + otherHeights;
|
||||
}
|
||||
|
||||
private int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) {
|
||||
final Rect displayFrame = new Rect();
|
||||
anchor.getWindowVisibleDisplayFrame(displayFrame);
|
||||
|
||||
final int[] anchorPos = new int[2];
|
||||
anchor.getLocationOnScreen(anchorPos);
|
||||
|
||||
int bottomEdge = displayFrame.bottom;
|
||||
if (ignoreBottomDecorations) {
|
||||
Resources res = anchor.getContext().getResources();
|
||||
bottomEdge = res.getDisplayMetrics().heightPixels;
|
||||
}
|
||||
final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset;
|
||||
final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset;
|
||||
|
||||
// anchorPos[1] is distance from anchor to top of screen
|
||||
int returnedHeight = Math.max(distanceToBottom, distanceToTop);
|
||||
if (mPopup.getBackground() != null) {
|
||||
mPopup.getBackground().getPadding(mTempRect);
|
||||
returnedHeight -= mTempRect.top + mTempRect.bottom;
|
||||
}
|
||||
|
||||
return returnedHeight;
|
||||
}
|
||||
|
||||
private int measureHeightOfChildren(int widthMeasureSpec, int startPosition, int endPosition,
|
||||
final int maxHeight, int disallowPartialChildPosition) {
|
||||
|
||||
final ListAdapter adapter = mAdapter;
|
||||
if (adapter == null) {
|
||||
return mDropDownList.getListPaddingTop() + mDropDownList.getListPaddingBottom();
|
||||
}
|
||||
|
||||
// Include the padding of the list
|
||||
int returnedHeight = mDropDownList.getListPaddingTop() + mDropDownList.getListPaddingBottom();
|
||||
final int dividerHeight = ((mDropDownList.getDividerHeight() > 0) && mDropDownList.getDivider() != null) ? mDropDownList.getDividerHeight() : 0;
|
||||
// The previous height value that was less than maxHeight and contained
|
||||
// no partial children
|
||||
int prevHeightWithoutPartialChild = 0;
|
||||
int i;
|
||||
View child;
|
||||
|
||||
// mItemCount - 1 since endPosition parameter is inclusive
|
||||
endPosition = (endPosition == -1/*NO_POSITION*/) ? adapter.getCount() - 1 : endPosition;
|
||||
|
||||
for (i = startPosition; i <= endPosition; ++i) {
|
||||
child = mAdapter.getView(i, null, mDropDownList);
|
||||
if (mDropDownList.getCacheColorHint() != 0) {
|
||||
child.setDrawingCacheBackgroundColor(mDropDownList.getCacheColorHint());
|
||||
}
|
||||
|
||||
measureScrapChild(child, i, widthMeasureSpec);
|
||||
|
||||
if (i > 0) {
|
||||
// Count the divider for all but one child
|
||||
returnedHeight += dividerHeight;
|
||||
}
|
||||
|
||||
returnedHeight += child.getMeasuredHeight();
|
||||
|
||||
if (returnedHeight >= maxHeight) {
|
||||
// We went over, figure out which height to return. If returnedHeight > maxHeight,
|
||||
// then the i'th position did not fit completely.
|
||||
return (disallowPartialChildPosition >= 0) // Disallowing is enabled (> -1)
|
||||
&& (i > disallowPartialChildPosition) // We've past the min pos
|
||||
&& (prevHeightWithoutPartialChild > 0) // We have a prev height
|
||||
&& (returnedHeight != maxHeight) // i'th child did not fit completely
|
||||
? prevHeightWithoutPartialChild
|
||||
: maxHeight;
|
||||
}
|
||||
|
||||
if ((disallowPartialChildPosition >= 0) && (i >= disallowPartialChildPosition)) {
|
||||
prevHeightWithoutPartialChild = returnedHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, we went through the range of children, and they each
|
||||
// completely fit, so return the returnedHeight
|
||||
return returnedHeight;
|
||||
}
|
||||
private void measureScrapChild(View child, int position, int widthMeasureSpec) {
|
||||
ListView.LayoutParams p = (ListView.LayoutParams) child.getLayoutParams();
|
||||
if (p == null) {
|
||||
p = new ListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, 0);
|
||||
child.setLayoutParams(p);
|
||||
}
|
||||
//XXX p.viewType = mAdapter.getItemViewType(position);
|
||||
//XXX p.forceAdd = true;
|
||||
|
||||
int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
|
||||
mDropDownList.getPaddingLeft() + mDropDownList.getPaddingRight(), p.width);
|
||||
int lpHeight = p.height;
|
||||
int childHeightSpec;
|
||||
if (lpHeight > 0) {
|
||||
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
|
||||
} else {
|
||||
childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
}
|
||||
child.measure(childWidthSpec, childHeightSpec);
|
||||
}
|
||||
|
||||
private static class DropDownListView extends ListView {
|
||||
/*
|
||||
* WARNING: This is a workaround for a touch mode issue.
|
||||
*
|
||||
* Touch mode is propagated lazily to windows. This causes problems in
|
||||
* the following scenario:
|
||||
* - Type something in the AutoCompleteTextView and get some results
|
||||
* - Move down with the d-pad to select an item in the list
|
||||
* - Move up with the d-pad until the selection disappears
|
||||
* - Type more text in the AutoCompleteTextView *using the soft keyboard*
|
||||
* and get new results; you are now in touch mode
|
||||
* - The selection comes back on the first item in the list, even though
|
||||
* the list is supposed to be in touch mode
|
||||
*
|
||||
* Using the soft keyboard triggers the touch mode change but that change
|
||||
* is propagated to our window only after the first list layout, therefore
|
||||
* after the list attempts to resurrect the selection.
|
||||
*
|
||||
* The trick to work around this issue is to pretend the list is in touch
|
||||
* mode when we know that the selection should not appear, that is when
|
||||
* we know the user moved the selection away from the list.
|
||||
*
|
||||
* This boolean is set to true whenever we explicitly hide the list's
|
||||
* selection and reset to false whenever we know the user moved the
|
||||
* selection back to the list.
|
||||
*
|
||||
* When this boolean is true, isInTouchMode() returns true, otherwise it
|
||||
* returns super.isInTouchMode().
|
||||
*/
|
||||
private boolean mListSelectionHidden;
|
||||
|
||||
private boolean mHijackFocus;
|
||||
|
||||
public DropDownListView(Context context, boolean hijackFocus) {
|
||||
super(context, null, /*com.android.internal.*/R.attr.dropDownListViewStyle);
|
||||
mHijackFocus = hijackFocus;
|
||||
// TODO: Add an API to control this
|
||||
setCacheColorHint(0); // Transparent, since the background drawable could be anything.
|
||||
}
|
||||
|
||||
//XXX @Override
|
||||
//View obtainView(int position, boolean[] isScrap) {
|
||||
// View view = super.obtainView(position, isScrap);
|
||||
|
||||
// if (view instanceof TextView) {
|
||||
// ((TextView) view).setHorizontallyScrolling(true);
|
||||
// }
|
||||
|
||||
// return view;
|
||||
//}
|
||||
|
||||
@Override
|
||||
public boolean isInTouchMode() {
|
||||
// WARNING: Please read the comment where mListSelectionHidden is declared
|
||||
return (mHijackFocus && mListSelectionHidden) || super.isInTouchMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasWindowFocus() {
|
||||
return mHijackFocus || super.hasWindowFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFocused() {
|
||||
return mHijackFocus || super.isFocused();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFocus() {
|
||||
return mHijackFocus || super.hasFocus();
|
||||
}
|
||||
}
|
||||
|
||||
private class PopupDataSetObserver extends DataSetObserver {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
if (isShowing()) {
|
||||
// Resize the popup to fit new content
|
||||
show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInvalidated() {
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
private class ListSelectorHider implements Runnable {
|
||||
public void run() {
|
||||
clearListSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private class ResizePopupRunnable implements Runnable {
|
||||
public void run() {
|
||||
if (mDropDownList != null && mDropDownList.getCount() > mDropDownList.getChildCount() &&
|
||||
mDropDownList.getChildCount() <= mListItemExpandMaximum) {
|
||||
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
|
||||
show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PopupTouchInterceptor implements OnTouchListener {
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
final int action = event.getAction();
|
||||
final int x = (int) event.getX();
|
||||
final int y = (int) event.getY();
|
||||
|
||||
if (action == MotionEvent.ACTION_DOWN &&
|
||||
mPopup != null && mPopup.isShowing() &&
|
||||
(x >= 0 && x < mPopup.getWidth() && y >= 0 && y < mPopup.getHeight())) {
|
||||
mHandler.postDelayed(mResizePopupRunnable, EXPAND_LIST_TIMEOUT);
|
||||
} else if (action == MotionEvent.ACTION_UP) {
|
||||
mHandler.removeCallbacks(mResizePopupRunnable);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class PopupScrollListener implements ListView.OnScrollListener {
|
||||
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
|
||||
int totalItemCount) {
|
||||
|
||||
}
|
||||
|
||||
public void onScrollStateChanged(AbsListView view, int scrollState) {
|
||||
if (scrollState == SCROLL_STATE_TOUCH_SCROLL &&
|
||||
!isInputMethodNotNeeded() && mPopup.getContentView() != null) {
|
||||
mHandler.removeCallbacks(mResizePopupRunnable);
|
||||
mResizePopupRunnable.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,703 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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.actionbarsherlock.internal.widget;
|
||||
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
import com.actionbarsherlock.R;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.res.TypedArray;
|
||||
import android.database.DataSetObserver;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.PopupWindow;
|
||||
import android.widget.SpinnerAdapter;
|
||||
|
||||
|
||||
/**
|
||||
* A view that displays one child at a time and lets the user pick among them.
|
||||
* The items in the Spinner come from the {@link Adapter} associated with
|
||||
* this view.
|
||||
*
|
||||
* <p>See the <a href="{@docRoot}resources/tutorials/views/hello-spinner.html">Spinner
|
||||
* tutorial</a>.</p>
|
||||
*
|
||||
* @attr ref android.R.styleable#Spinner_prompt
|
||||
*/
|
||||
public class IcsSpinner extends IcsAbsSpinner implements OnClickListener {
|
||||
//private static final String TAG = "Spinner";
|
||||
|
||||
// Only measure this many items to get a decent max width.
|
||||
private static final int MAX_ITEMS_MEASURED = 15;
|
||||
|
||||
/**
|
||||
* Use a dialog window for selecting spinner options.
|
||||
*/
|
||||
//public static final int MODE_DIALOG = 0;
|
||||
|
||||
/**
|
||||
* Use a dropdown anchored to the Spinner for selecting spinner options.
|
||||
*/
|
||||
public static final int MODE_DROPDOWN = 1;
|
||||
|
||||
/**
|
||||
* Use the theme-supplied value to select the dropdown mode.
|
||||
*/
|
||||
//private static final int MODE_THEME = -1;
|
||||
|
||||
private SpinnerPopup mPopup;
|
||||
private DropDownAdapter mTempAdapter;
|
||||
int mDropDownWidth;
|
||||
|
||||
private int mGravity;
|
||||
private boolean mDisableChildrenWhenDisabled;
|
||||
|
||||
private Rect mTempRect = new Rect();
|
||||
|
||||
public IcsSpinner(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, R.attr.actionDropDownStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new spinner with the given context's theme, the supplied attribute set,
|
||||
* and default style.
|
||||
*
|
||||
* @param context The Context the view is running in, through which it can
|
||||
* access the current theme, resources, etc.
|
||||
* @param attrs The attributes of the XML tag that is inflating the view.
|
||||
* @param defStyle The default style to apply to this view. If 0, no style
|
||||
* will be applied (beyond what is included in the theme). This may
|
||||
* either be an attribute resource, whose value will be retrieved
|
||||
* from the current theme, or an explicit style resource.
|
||||
*/
|
||||
public IcsSpinner(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
R.styleable.SherlockSpinner, defStyle, 0);
|
||||
|
||||
|
||||
DropdownPopup popup = new DropdownPopup(context, attrs, defStyle);
|
||||
|
||||
mDropDownWidth = a.getLayoutDimension(
|
||||
R.styleable.SherlockSpinner_android_dropDownWidth,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
popup.setBackgroundDrawable(a.getDrawable(
|
||||
R.styleable.SherlockSpinner_android_popupBackground));
|
||||
final int verticalOffset = a.getDimensionPixelOffset(
|
||||
R.styleable.SherlockSpinner_android_dropDownVerticalOffset, 0);
|
||||
if (verticalOffset != 0) {
|
||||
popup.setVerticalOffset(verticalOffset);
|
||||
}
|
||||
|
||||
final int horizontalOffset = a.getDimensionPixelOffset(
|
||||
R.styleable.SherlockSpinner_android_dropDownHorizontalOffset, 0);
|
||||
if (horizontalOffset != 0) {
|
||||
popup.setHorizontalOffset(horizontalOffset);
|
||||
}
|
||||
|
||||
mPopup = popup;
|
||||
|
||||
mGravity = a.getInt(R.styleable.SherlockSpinner_android_gravity, Gravity.CENTER);
|
||||
|
||||
mPopup.setPromptText(a.getString(R.styleable.SherlockSpinner_android_prompt));
|
||||
|
||||
mDisableChildrenWhenDisabled = true;
|
||||
|
||||
a.recycle();
|
||||
|
||||
// Base constructor can call setAdapter before we initialize mPopup.
|
||||
// Finish setting things up if this happened.
|
||||
if (mTempAdapter != null) {
|
||||
mPopup.setAdapter(mTempAdapter);
|
||||
mTempAdapter = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
if (mDisableChildrenWhenDisabled) {
|
||||
final int count = getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
getChildAt(i).setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes how the selected item view is positioned. Currently only the horizontal component
|
||||
* is used. The default is determined by the current theme.
|
||||
*
|
||||
* @param gravity See {@link android.view.Gravity}
|
||||
*
|
||||
* @attr ref android.R.styleable#Spinner_gravity
|
||||
*/
|
||||
public void setGravity(int gravity) {
|
||||
if (mGravity != gravity) {
|
||||
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
|
||||
gravity |= Gravity.LEFT;
|
||||
}
|
||||
mGravity = gravity;
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdapter(SpinnerAdapter adapter) {
|
||||
super.setAdapter(adapter);
|
||||
|
||||
if (mPopup != null) {
|
||||
mPopup.setAdapter(new DropDownAdapter(adapter));
|
||||
} else {
|
||||
mTempAdapter = new DropDownAdapter(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBaseline() {
|
||||
View child = null;
|
||||
|
||||
if (getChildCount() > 0) {
|
||||
child = getChildAt(0);
|
||||
} else if (mAdapter != null && mAdapter.getCount() > 0) {
|
||||
child = makeAndAddView(0);
|
||||
mRecycler.put(0, child);
|
||||
removeAllViewsInLayout();
|
||||
}
|
||||
|
||||
if (child != null) {
|
||||
final int childBaseline = child.getBaseline();
|
||||
return childBaseline >= 0 ? child.getTop() + childBaseline : -1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
|
||||
if (mPopup != null && mPopup.isShowing()) {
|
||||
mPopup.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>A spinner does not support item click events. Calling this method
|
||||
* will raise an exception.</p>
|
||||
*
|
||||
* @param l this listener will be ignored
|
||||
*/
|
||||
@Override
|
||||
public void setOnItemClickListener(OnItemClickListener l) {
|
||||
throw new RuntimeException("setOnItemClickListener cannot be used with a spinner.");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
if (mPopup != null && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) {
|
||||
final int measuredWidth = getMeasuredWidth();
|
||||
setMeasuredDimension(Math.min(Math.max(measuredWidth,
|
||||
measureContentWidth(getAdapter(), getBackground())),
|
||||
MeasureSpec.getSize(widthMeasureSpec)),
|
||||
getMeasuredHeight());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see android.view.View#onLayout(boolean,int,int,int,int)
|
||||
*
|
||||
* Creates and positions all views
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
super.onLayout(changed, l, t, r, b);
|
||||
mInLayout = true;
|
||||
layout(0, false);
|
||||
mInLayout = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and positions all views for this Spinner.
|
||||
*
|
||||
* @param delta Change in the selected position. +1 moves selection is moving to the right,
|
||||
* so views are scrolling to the left. -1 means selection is moving to the left.
|
||||
*/
|
||||
@Override
|
||||
void layout(int delta, boolean animate) {
|
||||
int childrenLeft = mSpinnerPadding.left;
|
||||
int childrenWidth = getRight() - getLeft() - mSpinnerPadding.left - mSpinnerPadding.right;
|
||||
|
||||
if (mDataChanged) {
|
||||
handleDataChanged();
|
||||
}
|
||||
|
||||
// Handle the empty set by removing all views
|
||||
if (mItemCount == 0) {
|
||||
resetList();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mNextSelectedPosition >= 0) {
|
||||
setSelectedPositionInt(mNextSelectedPosition);
|
||||
}
|
||||
|
||||
recycleAllViews();
|
||||
|
||||
// Clear out old views
|
||||
removeAllViewsInLayout();
|
||||
|
||||
// Make selected view and position it
|
||||
mFirstPosition = mSelectedPosition;
|
||||
View sel = makeAndAddView(mSelectedPosition);
|
||||
int width = sel.getMeasuredWidth();
|
||||
int selectedOffset = childrenLeft;
|
||||
switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
|
||||
case Gravity.CENTER_HORIZONTAL:
|
||||
selectedOffset = childrenLeft + (childrenWidth / 2) - (width / 2);
|
||||
break;
|
||||
case Gravity.RIGHT:
|
||||
selectedOffset = childrenLeft + childrenWidth - width;
|
||||
break;
|
||||
}
|
||||
sel.offsetLeftAndRight(selectedOffset);
|
||||
|
||||
// Flush any cached views that did not get reused above
|
||||
mRecycler.clear();
|
||||
|
||||
invalidate();
|
||||
|
||||
checkSelectionChanged();
|
||||
|
||||
mDataChanged = false;
|
||||
mNeedSync = false;
|
||||
setNextSelectedPositionInt(mSelectedPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a view, either by pulling an existing view from the recycler or
|
||||
* by getting a new one from the adapter. If we are animating, make sure
|
||||
* there is enough information in the view's layout parameters to animate
|
||||
* from the old to new positions.
|
||||
*
|
||||
* @param position Position in the spinner for the view to obtain
|
||||
* @return A view that has been added to the spinner
|
||||
*/
|
||||
private View makeAndAddView(int position) {
|
||||
|
||||
View child;
|
||||
|
||||
if (!mDataChanged) {
|
||||
child = mRecycler.get(position);
|
||||
if (child != null) {
|
||||
// Position the view
|
||||
setUpChild(child);
|
||||
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing found in the recycler -- ask the adapter for a view
|
||||
child = mAdapter.getView(position, null, this);
|
||||
|
||||
// Position the view
|
||||
setUpChild(child);
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for makeAndAddView to set the position of a view
|
||||
* and fill out its layout paramters.
|
||||
*
|
||||
* @param child The view to position
|
||||
*/
|
||||
private void setUpChild(View child) {
|
||||
|
||||
// Respect layout params that are already in the view. Otherwise
|
||||
// make some up...
|
||||
ViewGroup.LayoutParams lp = child.getLayoutParams();
|
||||
if (lp == null) {
|
||||
lp = generateDefaultLayoutParams();
|
||||
}
|
||||
|
||||
addViewInLayout(child, 0, lp);
|
||||
|
||||
child.setSelected(hasFocus());
|
||||
if (mDisableChildrenWhenDisabled) {
|
||||
child.setEnabled(isEnabled());
|
||||
}
|
||||
|
||||
// Get measure specs
|
||||
int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec,
|
||||
mSpinnerPadding.top + mSpinnerPadding.bottom, lp.height);
|
||||
int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
|
||||
mSpinnerPadding.left + mSpinnerPadding.right, lp.width);
|
||||
|
||||
// Measure child
|
||||
child.measure(childWidthSpec, childHeightSpec);
|
||||
|
||||
int childLeft;
|
||||
int childRight;
|
||||
|
||||
// Position vertically based on gravity setting
|
||||
int childTop = mSpinnerPadding.top
|
||||
+ ((getMeasuredHeight() - mSpinnerPadding.bottom -
|
||||
mSpinnerPadding.top - child.getMeasuredHeight()) / 2);
|
||||
int childBottom = childTop + child.getMeasuredHeight();
|
||||
|
||||
int width = child.getMeasuredWidth();
|
||||
childLeft = 0;
|
||||
childRight = childLeft + width;
|
||||
|
||||
child.layout(childLeft, childTop, childRight, childBottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performClick() {
|
||||
boolean handled = super.performClick();
|
||||
|
||||
if (!handled) {
|
||||
handled = true;
|
||||
|
||||
if (!mPopup.isShowing()) {
|
||||
mPopup.show();
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
setSelection(which);
|
||||
dialog.dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prompt to display when the dialog is shown.
|
||||
* @param prompt the prompt to set
|
||||
*/
|
||||
public void setPrompt(CharSequence prompt) {
|
||||
mPopup.setPromptText(prompt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prompt to display when the dialog is shown.
|
||||
* @param promptId the resource ID of the prompt to display when the dialog is shown
|
||||
*/
|
||||
public void setPromptId(int promptId) {
|
||||
setPrompt(getContext().getText(promptId));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The prompt to display when the dialog is shown
|
||||
*/
|
||||
public CharSequence getPrompt() {
|
||||
return mPopup.getHintText();
|
||||
}
|
||||
|
||||
int measureContentWidth(SpinnerAdapter adapter, Drawable background) {
|
||||
if (adapter == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int width = 0;
|
||||
View itemView = null;
|
||||
int itemType = 0;
|
||||
final int widthMeasureSpec =
|
||||
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
final int heightMeasureSpec =
|
||||
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
|
||||
// Make sure the number of items we'll measure is capped. If it's a huge data set
|
||||
// with wildly varying sizes, oh well.
|
||||
int start = Math.max(0, getSelectedItemPosition());
|
||||
final int end = Math.min(adapter.getCount(), start + MAX_ITEMS_MEASURED);
|
||||
final int count = end - start;
|
||||
start = Math.max(0, start - (MAX_ITEMS_MEASURED - count));
|
||||
for (int i = start; i < end; i++) {
|
||||
final int positionType = adapter.getItemViewType(i);
|
||||
if (positionType != itemType) {
|
||||
itemType = positionType;
|
||||
itemView = null;
|
||||
}
|
||||
itemView = adapter.getView(i, itemView, this);
|
||||
if (itemView.getLayoutParams() == null) {
|
||||
itemView.setLayoutParams(new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
}
|
||||
itemView.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
width = Math.max(width, itemView.getMeasuredWidth());
|
||||
}
|
||||
|
||||
// Add background padding to measured width
|
||||
if (background != null) {
|
||||
background.getPadding(mTempRect);
|
||||
width += mTempRect.left + mTempRect.right;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Wrapper class for an Adapter. Transforms the embedded Adapter instance
|
||||
* into a ListAdapter.</p>
|
||||
*/
|
||||
private static class DropDownAdapter implements ListAdapter, SpinnerAdapter {
|
||||
private SpinnerAdapter mAdapter;
|
||||
private ListAdapter mListAdapter;
|
||||
|
||||
/**
|
||||
* <p>Creates a new ListAdapter wrapper for the specified adapter.</p>
|
||||
*
|
||||
* @param adapter the Adapter to transform into a ListAdapter
|
||||
*/
|
||||
public DropDownAdapter(SpinnerAdapter adapter) {
|
||||
this.mAdapter = adapter;
|
||||
if (adapter instanceof ListAdapter) {
|
||||
this.mListAdapter = (ListAdapter) adapter;
|
||||
}
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return mAdapter == null ? 0 : mAdapter.getCount();
|
||||
}
|
||||
|
||||
public Object getItem(int position) {
|
||||
return mAdapter == null ? null : mAdapter.getItem(position);
|
||||
}
|
||||
|
||||
public long getItemId(int position) {
|
||||
return mAdapter == null ? -1 : mAdapter.getItemId(position);
|
||||
}
|
||||
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
return getDropDownView(position, convertView, parent);
|
||||
}
|
||||
|
||||
public View getDropDownView(int position, View convertView, ViewGroup parent) {
|
||||
return mAdapter == null ? null :
|
||||
mAdapter.getDropDownView(position, convertView, parent);
|
||||
}
|
||||
|
||||
public boolean hasStableIds() {
|
||||
return mAdapter != null && mAdapter.hasStableIds();
|
||||
}
|
||||
|
||||
public void registerDataSetObserver(DataSetObserver observer) {
|
||||
if (mAdapter != null) {
|
||||
mAdapter.registerDataSetObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterDataSetObserver(DataSetObserver observer) {
|
||||
if (mAdapter != null) {
|
||||
mAdapter.unregisterDataSetObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
|
||||
* Otherwise, return true.
|
||||
*/
|
||||
public boolean areAllItemsEnabled() {
|
||||
final ListAdapter adapter = mListAdapter;
|
||||
if (adapter != null) {
|
||||
return adapter.areAllItemsEnabled();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
|
||||
* Otherwise, return true.
|
||||
*/
|
||||
public boolean isEnabled(int position) {
|
||||
final ListAdapter adapter = mListAdapter;
|
||||
if (adapter != null) {
|
||||
return adapter.isEnabled(position);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public int getItemViewType(int position) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getViewTypeCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return getCount() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements some sort of popup selection interface for selecting a spinner option.
|
||||
* Allows for different spinner modes.
|
||||
*/
|
||||
private interface SpinnerPopup {
|
||||
public void setAdapter(ListAdapter adapter);
|
||||
|
||||
/**
|
||||
* Show the popup
|
||||
*/
|
||||
public void show();
|
||||
|
||||
/**
|
||||
* Dismiss the popup
|
||||
*/
|
||||
public void dismiss();
|
||||
|
||||
/**
|
||||
* @return true if the popup is showing, false otherwise.
|
||||
*/
|
||||
public boolean isShowing();
|
||||
|
||||
/**
|
||||
* Set hint text to be displayed to the user. This should provide
|
||||
* a description of the choice being made.
|
||||
* @param hintText Hint text to set.
|
||||
*/
|
||||
public void setPromptText(CharSequence hintText);
|
||||
public CharSequence getHintText();
|
||||
}
|
||||
|
||||
/*
|
||||
private class DialogPopup implements SpinnerPopup, DialogInterface.OnClickListener {
|
||||
private AlertDialog mPopup;
|
||||
private ListAdapter mListAdapter;
|
||||
private CharSequence mPrompt;
|
||||
|
||||
public void dismiss() {
|
||||
mPopup.dismiss();
|
||||
mPopup = null;
|
||||
}
|
||||
|
||||
public boolean isShowing() {
|
||||
return mPopup != null ? mPopup.isShowing() : false;
|
||||
}
|
||||
|
||||
public void setAdapter(ListAdapter adapter) {
|
||||
mListAdapter = adapter;
|
||||
}
|
||||
|
||||
public void setPromptText(CharSequence hintText) {
|
||||
mPrompt = hintText;
|
||||
}
|
||||
|
||||
public CharSequence getHintText() {
|
||||
return mPrompt;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
if (mPrompt != null) {
|
||||
builder.setTitle(mPrompt);
|
||||
}
|
||||
mPopup = builder.setSingleChoiceItems(mListAdapter,
|
||||
getSelectedItemPosition(), this).show();
|
||||
}
|
||||
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
setSelection(which);
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
private class DropdownPopup extends IcsListPopupWindow implements SpinnerPopup {
|
||||
private CharSequence mHintText;
|
||||
private ListAdapter mAdapter;
|
||||
|
||||
public DropdownPopup(Context context, AttributeSet attrs, int defStyleRes) {
|
||||
super(context, attrs, 0, defStyleRes);
|
||||
|
||||
setAnchorView(IcsSpinner.this);
|
||||
setModal(true);
|
||||
setPromptPosition(POSITION_PROMPT_ABOVE);
|
||||
setOnItemClickListener(new OnItemClickListener() {
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void onItemClick(AdapterView parent, View v, int position, long id) {
|
||||
IcsSpinner.this.setSelection(position);
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdapter(ListAdapter adapter) {
|
||||
super.setAdapter(adapter);
|
||||
mAdapter = adapter;
|
||||
}
|
||||
|
||||
public CharSequence getHintText() {
|
||||
return mHintText;
|
||||
}
|
||||
|
||||
public void setPromptText(CharSequence hintText) {
|
||||
// Hint text is ignored for dropdowns, but maintain it here.
|
||||
mHintText = hintText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
final int spinnerPaddingLeft = IcsSpinner.this.getPaddingLeft();
|
||||
if (mDropDownWidth == WRAP_CONTENT) {
|
||||
final int spinnerWidth = IcsSpinner.this.getWidth();
|
||||
final int spinnerPaddingRight = IcsSpinner.this.getPaddingRight();
|
||||
setContentWidth(Math.max(
|
||||
measureContentWidth((SpinnerAdapter) mAdapter, getBackground()),
|
||||
spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight));
|
||||
} else if (mDropDownWidth == MATCH_PARENT) {
|
||||
final int spinnerWidth = IcsSpinner.this.getWidth();
|
||||
final int spinnerPaddingRight = IcsSpinner.this.getPaddingRight();
|
||||
setContentWidth(spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight);
|
||||
} else {
|
||||
setContentWidth(mDropDownWidth);
|
||||
}
|
||||
final Drawable background = getBackground();
|
||||
int bgOffset = 0;
|
||||
if (background != null) {
|
||||
background.getPadding(mTempRect);
|
||||
bgOffset = -mTempRect.left;
|
||||
}
|
||||
setHorizontalOffset(bgOffset + spinnerPaddingLeft);
|
||||
setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
|
||||
super.show();
|
||||
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
|
||||
setSelection(IcsSpinner.this.getSelectedItemPosition());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
final class IcsView {
|
||||
//No instances
|
||||
private IcsView() {}
|
||||
|
||||
/**
|
||||
* Return only the state bits of {@link #getMeasuredWidthAndState()}
|
||||
* and {@link #getMeasuredHeightAndState()}, combined into one integer.
|
||||
* The width component is in the regular bits {@link #MEASURED_STATE_MASK}
|
||||
* and the height component is at the shifted bits
|
||||
* {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}.
|
||||
*/
|
||||
public static int getMeasuredStateInt(View child) {
|
||||
return (child.getMeasuredWidth()&View.MEASURED_STATE_MASK)
|
||||
| ((child.getMeasuredHeight()>>View.MEASURED_HEIGHT_STATE_SHIFT)
|
||||
& (View.MEASURED_STATE_MASK>>View.MEASURED_HEIGHT_STATE_SHIFT));
|
||||
}
|
||||
}
|
@ -1,546 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 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.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils.TruncateAt;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.app.ActionBar;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Animator;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.widget.NineHorizontalScrollView;
|
||||
|
||||
/**
|
||||
* This widget implements the dynamic action bar tab behavior that can change
|
||||
* across different configurations or circumstances.
|
||||
*/
|
||||
public class ScrollingTabContainerView extends NineHorizontalScrollView
|
||||
implements IcsAdapterView.OnItemSelectedListener {
|
||||
//UNUSED private static final String TAG = "ScrollingTabContainerView";
|
||||
Runnable mTabSelector;
|
||||
private TabClickListener mTabClickListener;
|
||||
|
||||
private IcsLinearLayout mTabLayout;
|
||||
private IcsSpinner mTabSpinner;
|
||||
private boolean mAllowCollapse;
|
||||
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
int mMaxTabWidth;
|
||||
private int mContentHeight;
|
||||
private int mSelectedTabIndex;
|
||||
|
||||
protected Animator mVisibilityAnim;
|
||||
protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
|
||||
|
||||
private static final /*Time*/Interpolator sAlphaInterpolator = new DecelerateInterpolator();
|
||||
|
||||
private static final int FADE_DURATION = 200;
|
||||
|
||||
public ScrollingTabContainerView(Context context) {
|
||||
super(context);
|
||||
setHorizontalScrollBarEnabled(false);
|
||||
|
||||
TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.SherlockActionBar,
|
||||
R.attr.actionBarStyle, 0);
|
||||
setContentHeight(a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0));
|
||||
a.recycle();
|
||||
|
||||
mInflater = LayoutInflater.from(context);
|
||||
|
||||
mTabLayout = createTabLayout();
|
||||
addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
final boolean lockedExpanded = widthMode == MeasureSpec.EXACTLY;
|
||||
setFillViewport(lockedExpanded);
|
||||
|
||||
final int childCount = mTabLayout.getChildCount();
|
||||
if (childCount > 1 &&
|
||||
(widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) {
|
||||
if (childCount > 2) {
|
||||
mMaxTabWidth = (int) (MeasureSpec.getSize(widthMeasureSpec) * 0.4f);
|
||||
} else {
|
||||
mMaxTabWidth = MeasureSpec.getSize(widthMeasureSpec) / 2;
|
||||
}
|
||||
} else {
|
||||
mMaxTabWidth = -1;
|
||||
}
|
||||
|
||||
heightMeasureSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.EXACTLY);
|
||||
|
||||
final boolean canCollapse = !lockedExpanded && mAllowCollapse;
|
||||
|
||||
if (canCollapse) {
|
||||
// See if we should expand
|
||||
mTabLayout.measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec);
|
||||
if (mTabLayout.getMeasuredWidth() > MeasureSpec.getSize(widthMeasureSpec)) {
|
||||
performCollapse();
|
||||
} else {
|
||||
performExpand();
|
||||
}
|
||||
} else {
|
||||
performExpand();
|
||||
}
|
||||
|
||||
final int oldWidth = getMeasuredWidth();
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
final int newWidth = getMeasuredWidth();
|
||||
|
||||
if (lockedExpanded && oldWidth != newWidth) {
|
||||
// Recenter the tab display if we're at a new (scrollable) size.
|
||||
setTabSelected(mSelectedTabIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this view is collapsed into a dropdown menu instead
|
||||
* of traditional tabs.
|
||||
* @return true if showing as a spinner
|
||||
*/
|
||||
private boolean isCollapsed() {
|
||||
return mTabSpinner != null && mTabSpinner.getParent() == this;
|
||||
}
|
||||
|
||||
public void setAllowCollapse(boolean allowCollapse) {
|
||||
mAllowCollapse = allowCollapse;
|
||||
}
|
||||
|
||||
private void performCollapse() {
|
||||
if (isCollapsed()) return;
|
||||
|
||||
if (mTabSpinner == null) {
|
||||
mTabSpinner = createSpinner();
|
||||
}
|
||||
removeView(mTabLayout);
|
||||
addView(mTabSpinner, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
if (mTabSpinner.getAdapter() == null) {
|
||||
mTabSpinner.setAdapter(new TabAdapter());
|
||||
}
|
||||
if (mTabSelector != null) {
|
||||
removeCallbacks(mTabSelector);
|
||||
mTabSelector = null;
|
||||
}
|
||||
mTabSpinner.setSelection(mSelectedTabIndex);
|
||||
}
|
||||
|
||||
private boolean performExpand() {
|
||||
if (!isCollapsed()) return false;
|
||||
|
||||
removeView(mTabSpinner);
|
||||
addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
setTabSelected(mTabSpinner.getSelectedItemPosition());
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setTabSelected(int position) {
|
||||
mSelectedTabIndex = position;
|
||||
final int tabCount = mTabLayout.getChildCount();
|
||||
for (int i = 0; i < tabCount; i++) {
|
||||
final View child = mTabLayout.getChildAt(i);
|
||||
final boolean isSelected = i == position;
|
||||
child.setSelected(isSelected);
|
||||
if (isSelected) {
|
||||
animateToTab(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setContentHeight(int contentHeight) {
|
||||
mContentHeight = contentHeight;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
private IcsLinearLayout createTabLayout() {
|
||||
final IcsLinearLayout tabLayout = (IcsLinearLayout) LayoutInflater.from(getContext())
|
||||
.inflate(R.layout.abs__action_bar_tab_bar_view, null);
|
||||
tabLayout.setMeasureWithLargestChildEnabled(true);
|
||||
tabLayout.setLayoutParams(new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT));
|
||||
return tabLayout;
|
||||
}
|
||||
|
||||
private IcsSpinner createSpinner() {
|
||||
final IcsSpinner spinner = new IcsSpinner(getContext(), null,
|
||||
R.attr.actionDropDownStyle);
|
||||
spinner.setLayoutParams(new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT));
|
||||
spinner.setOnItemSelectedListener(this);
|
||||
return spinner;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
||||
// Action bar can change size on configuration changes.
|
||||
// Reread the desired height from the theme-specified style.
|
||||
TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.SherlockActionBar,
|
||||
R.attr.actionBarStyle, 0);
|
||||
setContentHeight(a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0));
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public void animateToVisibility(int visibility) {
|
||||
if (mVisibilityAnim != null) {
|
||||
mVisibilityAnim.cancel();
|
||||
}
|
||||
if (visibility == VISIBLE) {
|
||||
if (getVisibility() != VISIBLE) {
|
||||
setAlpha(0);
|
||||
}
|
||||
ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1);
|
||||
anim.setDuration(FADE_DURATION);
|
||||
anim.setInterpolator(sAlphaInterpolator);
|
||||
|
||||
anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
|
||||
anim.start();
|
||||
} else {
|
||||
ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0);
|
||||
anim.setDuration(FADE_DURATION);
|
||||
anim.setInterpolator(sAlphaInterpolator);
|
||||
|
||||
anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
|
||||
anim.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void animateToTab(final int position) {
|
||||
final View tabView = mTabLayout.getChildAt(position);
|
||||
if (mTabSelector != null) {
|
||||
removeCallbacks(mTabSelector);
|
||||
}
|
||||
mTabSelector = new Runnable() {
|
||||
public void run() {
|
||||
final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2;
|
||||
smoothScrollTo(scrollPos, 0);
|
||||
mTabSelector = null;
|
||||
}
|
||||
};
|
||||
post(mTabSelector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
if (mTabSelector != null) {
|
||||
// Re-post the selector we saved
|
||||
post(mTabSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if (mTabSelector != null) {
|
||||
removeCallbacks(mTabSelector);
|
||||
}
|
||||
}
|
||||
|
||||
private TabView createTabView(ActionBar.Tab tab, boolean forAdapter) {
|
||||
//Workaround for not being able to pass a defStyle on pre-3.0
|
||||
final TabView tabView = (TabView)mInflater.inflate(R.layout.abs__action_bar_tab, null);
|
||||
tabView.init(this, tab, forAdapter);
|
||||
|
||||
if (forAdapter) {
|
||||
tabView.setBackgroundDrawable(null);
|
||||
tabView.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT,
|
||||
mContentHeight));
|
||||
} else {
|
||||
tabView.setFocusable(true);
|
||||
|
||||
if (mTabClickListener == null) {
|
||||
mTabClickListener = new TabClickListener();
|
||||
}
|
||||
tabView.setOnClickListener(mTabClickListener);
|
||||
}
|
||||
return tabView;
|
||||
}
|
||||
|
||||
public void addTab(ActionBar.Tab tab, boolean setSelected) {
|
||||
TabView tabView = createTabView(tab, false);
|
||||
mTabLayout.addView(tabView, new IcsLinearLayout.LayoutParams(0,
|
||||
LayoutParams.MATCH_PARENT, 1));
|
||||
if (mTabSpinner != null) {
|
||||
((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
|
||||
}
|
||||
if (setSelected) {
|
||||
tabView.setSelected(true);
|
||||
}
|
||||
if (mAllowCollapse) {
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public void addTab(ActionBar.Tab tab, int position, boolean setSelected) {
|
||||
final TabView tabView = createTabView(tab, false);
|
||||
mTabLayout.addView(tabView, position, new IcsLinearLayout.LayoutParams(
|
||||
0, LayoutParams.MATCH_PARENT, 1));
|
||||
if (mTabSpinner != null) {
|
||||
((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
|
||||
}
|
||||
if (setSelected) {
|
||||
tabView.setSelected(true);
|
||||
}
|
||||
if (mAllowCollapse) {
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTab(int position) {
|
||||
((TabView) mTabLayout.getChildAt(position)).update();
|
||||
if (mTabSpinner != null) {
|
||||
((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
|
||||
}
|
||||
if (mAllowCollapse) {
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTabAt(int position) {
|
||||
mTabLayout.removeViewAt(position);
|
||||
if (mTabSpinner != null) {
|
||||
((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
|
||||
}
|
||||
if (mAllowCollapse) {
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAllTabs() {
|
||||
mTabLayout.removeAllViews();
|
||||
if (mTabSpinner != null) {
|
||||
((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
|
||||
}
|
||||
if (mAllowCollapse) {
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSelected(IcsAdapterView<?> parent, View view, int position, long id) {
|
||||
TabView tabView = (TabView) view;
|
||||
tabView.getTab().select();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(IcsAdapterView<?> parent) {
|
||||
}
|
||||
|
||||
public static class TabView extends LinearLayout {
|
||||
private ScrollingTabContainerView mParent;
|
||||
private ActionBar.Tab mTab;
|
||||
private CapitalizingTextView mTextView;
|
||||
private ImageView mIconView;
|
||||
private View mCustomView;
|
||||
|
||||
public TabView(Context context, AttributeSet attrs) {
|
||||
//TODO super(context, null, R.attr.actionBarTabStyle);
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public void init(ScrollingTabContainerView parent, ActionBar.Tab tab, boolean forList) {
|
||||
mParent = parent;
|
||||
mTab = tab;
|
||||
|
||||
if (forList) {
|
||||
setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
public void bindTab(ActionBar.Tab tab) {
|
||||
mTab = tab;
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
// Re-measure if we went beyond our maximum size.
|
||||
if (mParent.mMaxTabWidth > 0 && getMeasuredWidth() > mParent.mMaxTabWidth) {
|
||||
super.onMeasure(MeasureSpec.makeMeasureSpec(mParent.mMaxTabWidth, MeasureSpec.EXACTLY),
|
||||
heightMeasureSpec);
|
||||
}
|
||||
}
|
||||
|
||||
public void update() {
|
||||
final ActionBar.Tab tab = mTab;
|
||||
final View custom = tab.getCustomView();
|
||||
if (custom != null) {
|
||||
final ViewParent customParent = custom.getParent();
|
||||
if (customParent != this) {
|
||||
if (customParent != null) ((ViewGroup) customParent).removeView(custom);
|
||||
addView(custom);
|
||||
}
|
||||
mCustomView = custom;
|
||||
if (mTextView != null) mTextView.setVisibility(GONE);
|
||||
if (mIconView != null) {
|
||||
mIconView.setVisibility(GONE);
|
||||
mIconView.setImageDrawable(null);
|
||||
}
|
||||
} else {
|
||||
if (mCustomView != null) {
|
||||
removeView(mCustomView);
|
||||
mCustomView = null;
|
||||
}
|
||||
|
||||
final Drawable icon = tab.getIcon();
|
||||
final CharSequence text = tab.getText();
|
||||
|
||||
if (icon != null) {
|
||||
if (mIconView == null) {
|
||||
ImageView iconView = new ImageView(getContext());
|
||||
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.WRAP_CONTENT);
|
||||
lp.gravity = Gravity.CENTER_VERTICAL;
|
||||
iconView.setLayoutParams(lp);
|
||||
addView(iconView, 0);
|
||||
mIconView = iconView;
|
||||
}
|
||||
mIconView.setImageDrawable(icon);
|
||||
mIconView.setVisibility(VISIBLE);
|
||||
} else if (mIconView != null) {
|
||||
mIconView.setVisibility(GONE);
|
||||
mIconView.setImageDrawable(null);
|
||||
}
|
||||
|
||||
if (text != null) {
|
||||
if (mTextView == null) {
|
||||
CapitalizingTextView textView = new CapitalizingTextView(getContext(), null,
|
||||
R.attr.actionBarTabTextStyle);
|
||||
textView.setEllipsize(TruncateAt.END);
|
||||
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.WRAP_CONTENT);
|
||||
lp.gravity = Gravity.CENTER_VERTICAL;
|
||||
textView.setLayoutParams(lp);
|
||||
addView(textView);
|
||||
mTextView = textView;
|
||||
}
|
||||
mTextView.setTextCompat(text);
|
||||
mTextView.setVisibility(VISIBLE);
|
||||
} else if (mTextView != null) {
|
||||
mTextView.setVisibility(GONE);
|
||||
mTextView.setText(null);
|
||||
}
|
||||
|
||||
if (mIconView != null) {
|
||||
mIconView.setContentDescription(tab.getContentDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ActionBar.Tab getTab() {
|
||||
return mTab;
|
||||
}
|
||||
}
|
||||
|
||||
private class TabAdapter extends BaseAdapter {
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mTabLayout.getChildCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return ((TabView) mTabLayout.getChildAt(position)).getTab();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = createTabView((ActionBar.Tab) getItem(position), true);
|
||||
} else {
|
||||
((TabView) convertView).bindTab((ActionBar.Tab) getItem(position));
|
||||
}
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
|
||||
private class TabClickListener implements OnClickListener {
|
||||
public void onClick(View view) {
|
||||
TabView tabView = (TabView) view;
|
||||
tabView.getTab().select();
|
||||
final int tabCount = mTabLayout.getChildCount();
|
||||
for (int i = 0; i < tabCount; i++) {
|
||||
final View child = mTabLayout.getChildAt(i);
|
||||
child.setSelected(child == view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected class VisibilityAnimListener implements Animator.AnimatorListener {
|
||||
private boolean mCanceled = false;
|
||||
private int mFinalVisibility;
|
||||
|
||||
public VisibilityAnimListener withFinalVisibility(int visibility) {
|
||||
mFinalVisibility = visibility;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
setVisibility(VISIBLE);
|
||||
mVisibilityAnim = animation;
|
||||
mCanceled = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mCanceled) return;
|
||||
|
||||
mVisibilityAnim = null;
|
||||
setVisibility(mFinalVisibility);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
mCanceled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
}
|
||||
}
|
||||
}
|
@ -1,224 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.view;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a contextual mode of the user interface. Action modes can be used for
|
||||
* modal interactions with content and replace parts of the normal UI until finished.
|
||||
* Examples of good action modes include selection modes, search, content editing, etc.
|
||||
*/
|
||||
public abstract class ActionMode {
|
||||
private Object mTag;
|
||||
|
||||
/**
|
||||
* Set a tag object associated with this ActionMode.
|
||||
*
|
||||
* <p>Like the tag available to views, this allows applications to associate arbitrary
|
||||
* data with an ActionMode for later reference.
|
||||
*
|
||||
* @param tag Tag to associate with this ActionMode
|
||||
*
|
||||
* @see #getTag()
|
||||
*/
|
||||
public void setTag(Object tag) {
|
||||
mTag = tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the tag object associated with this ActionMode.
|
||||
*
|
||||
* <p>Like the tag available to views, this allows applications to associate arbitrary
|
||||
* data with an ActionMode for later reference.
|
||||
*
|
||||
* @return Tag associated with this ActionMode
|
||||
*
|
||||
* @see #setTag(Object)
|
||||
*/
|
||||
public Object getTag() {
|
||||
return mTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the title of the action mode. This method will have no visible effect if
|
||||
* a custom view has been set.
|
||||
*
|
||||
* @param title Title string to set
|
||||
*
|
||||
* @see #setTitle(int)
|
||||
* @see #setCustomView(View)
|
||||
*/
|
||||
public abstract void setTitle(CharSequence title);
|
||||
|
||||
/**
|
||||
* Set the title of the action mode. This method will have no visible effect if
|
||||
* a custom view has been set.
|
||||
*
|
||||
* @param resId Resource ID of a string to set as the title
|
||||
*
|
||||
* @see #setTitle(CharSequence)
|
||||
* @see #setCustomView(View)
|
||||
*/
|
||||
public abstract void setTitle(int resId);
|
||||
|
||||
/**
|
||||
* Set the subtitle of the action mode. This method will have no visible effect if
|
||||
* a custom view has been set.
|
||||
*
|
||||
* @param subtitle Subtitle string to set
|
||||
*
|
||||
* @see #setSubtitle(int)
|
||||
* @see #setCustomView(View)
|
||||
*/
|
||||
public abstract void setSubtitle(CharSequence subtitle);
|
||||
|
||||
/**
|
||||
* Set the subtitle of the action mode. This method will have no visible effect if
|
||||
* a custom view has been set.
|
||||
*
|
||||
* @param resId Resource ID of a string to set as the subtitle
|
||||
*
|
||||
* @see #setSubtitle(CharSequence)
|
||||
* @see #setCustomView(View)
|
||||
*/
|
||||
public abstract void setSubtitle(int resId);
|
||||
|
||||
/**
|
||||
* Set a custom view for this action mode. The custom view will take the place of
|
||||
* the title and subtitle. Useful for things like search boxes.
|
||||
*
|
||||
* @param view Custom view to use in place of the title/subtitle.
|
||||
*
|
||||
* @see #setTitle(CharSequence)
|
||||
* @see #setSubtitle(CharSequence)
|
||||
*/
|
||||
public abstract void setCustomView(View view);
|
||||
|
||||
/**
|
||||
* Invalidate the action mode and refresh menu content. The mode's
|
||||
* {@link ActionMode.Callback} will have its
|
||||
* {@link Callback#onPrepareActionMode(ActionMode, Menu)} method called.
|
||||
* If it returns true the menu will be scanned for updated content and any relevant changes
|
||||
* will be reflected to the user.
|
||||
*/
|
||||
public abstract void invalidate();
|
||||
|
||||
/**
|
||||
* Finish and close this action mode. The action mode's {@link ActionMode.Callback} will
|
||||
* have its {@link Callback#onDestroyActionMode(ActionMode)} method called.
|
||||
*/
|
||||
public abstract void finish();
|
||||
|
||||
/**
|
||||
* Returns the menu of actions that this action mode presents.
|
||||
* @return The action mode's menu.
|
||||
*/
|
||||
public abstract Menu getMenu();
|
||||
|
||||
/**
|
||||
* Returns the current title of this action mode.
|
||||
* @return Title text
|
||||
*/
|
||||
public abstract CharSequence getTitle();
|
||||
|
||||
/**
|
||||
* Returns the current subtitle of this action mode.
|
||||
* @return Subtitle text
|
||||
*/
|
||||
public abstract CharSequence getSubtitle();
|
||||
|
||||
/**
|
||||
* Returns the current custom view for this action mode.
|
||||
* @return The current custom view
|
||||
*/
|
||||
public abstract View getCustomView();
|
||||
|
||||
/**
|
||||
* Returns a {@link MenuInflater} with the ActionMode's context.
|
||||
*/
|
||||
public abstract MenuInflater getMenuInflater();
|
||||
|
||||
/**
|
||||
* Returns whether the UI presenting this action mode can take focus or not.
|
||||
* This is used by internal components within the framework that would otherwise
|
||||
* present an action mode UI that requires focus, such as an EditText as a custom view.
|
||||
*
|
||||
* @return true if the UI used to show this action mode can take focus
|
||||
* @hide Internal use only
|
||||
*/
|
||||
public boolean isUiFocusable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface for action modes. Supplied to
|
||||
* {@link View#startActionMode(Callback)}, a Callback
|
||||
* configures and handles events raised by a user's interaction with an action mode.
|
||||
*
|
||||
* <p>An action mode's lifecycle is as follows:
|
||||
* <ul>
|
||||
* <li>{@link Callback#onCreateActionMode(ActionMode, Menu)} once on initial
|
||||
* creation</li>
|
||||
* <li>{@link Callback#onPrepareActionMode(ActionMode, Menu)} after creation
|
||||
* and any time the {@link ActionMode} is invalidated</li>
|
||||
* <li>{@link Callback#onActionItemClicked(ActionMode, MenuItem)} any time a
|
||||
* contextual action button is clicked</li>
|
||||
* <li>{@link Callback#onDestroyActionMode(ActionMode)} when the action mode
|
||||
* is closed</li>
|
||||
* </ul>
|
||||
*/
|
||||
public interface Callback {
|
||||
/**
|
||||
* Called when action mode is first created. The menu supplied will be used to
|
||||
* generate action buttons for the action mode.
|
||||
*
|
||||
* @param mode ActionMode being created
|
||||
* @param menu Menu used to populate action buttons
|
||||
* @return true if the action mode should be created, false if entering this
|
||||
* mode should be aborted.
|
||||
*/
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu);
|
||||
|
||||
/**
|
||||
* Called to refresh an action mode's action menu whenever it is invalidated.
|
||||
*
|
||||
* @param mode ActionMode being prepared
|
||||
* @param menu Menu used to populate action buttons
|
||||
* @return true if the menu or action mode was updated, false otherwise.
|
||||
*/
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu);
|
||||
|
||||
/**
|
||||
* Called to report a user click on an action button.
|
||||
*
|
||||
* @param mode The current ActionMode
|
||||
* @param item The item that was clicked
|
||||
* @return true if this callback handled the event, false if the standard MenuItem
|
||||
* invocation should continue.
|
||||
*/
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item);
|
||||
|
||||
/**
|
||||
* Called when an action mode is about to be exited and destroyed.
|
||||
*
|
||||
* @param mode The current ActionMode being destroyed
|
||||
*/
|
||||
public void onDestroyActionMode(ActionMode mode);
|
||||
}
|
||||
}
|
@ -1,170 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 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.actionbarsherlock.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* This class is a mediator for accomplishing a given task, for example sharing a file.
|
||||
* It is responsible for creating a view that performs an action that accomplishes the task.
|
||||
* This class also implements other functions such a performing a default action.
|
||||
* <p>
|
||||
* An ActionProvider can be optionally specified for a {@link MenuItem} and in such a
|
||||
* case it will be responsible for creating the action view that appears in the
|
||||
* {@link android.app.ActionBar} as a substitute for the menu item when the item is
|
||||
* displayed as an action item. Also the provider is responsible for performing a
|
||||
* default action if a menu item placed on the overflow menu of the ActionBar is
|
||||
* selected and none of the menu item callbacks has handled the selection. For this
|
||||
* case the provider can also optionally provide a sub-menu for accomplishing the
|
||||
* task at hand.
|
||||
* </p>
|
||||
* <p>
|
||||
* There are two ways for using an action provider for creating and handling of action views:
|
||||
* <ul>
|
||||
* <li>
|
||||
* Setting the action provider on a {@link MenuItem} directly by calling
|
||||
* {@link MenuItem#setActionProvider(ActionProvider)}.
|
||||
* </li>
|
||||
* <li>
|
||||
* Declaring the action provider in the menu XML resource. For example:
|
||||
* <pre>
|
||||
* <code>
|
||||
* <item android:id="@+id/my_menu_item"
|
||||
* android:title="Title"
|
||||
* android:icon="@drawable/my_menu_item_icon"
|
||||
* android:showAsAction="ifRoom"
|
||||
* android:actionProviderClass="foo.bar.SomeActionProvider" />
|
||||
* </code>
|
||||
* </pre>
|
||||
* </li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @see MenuItem#setActionProvider(ActionProvider)
|
||||
* @see MenuItem#getActionProvider()
|
||||
*/
|
||||
public abstract class ActionProvider {
|
||||
private SubUiVisibilityListener mSubUiVisibilityListener;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param context Context for accessing resources.
|
||||
*/
|
||||
public ActionProvider(Context context) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for creating new action views.
|
||||
*
|
||||
* @return A new action view.
|
||||
*/
|
||||
public abstract View onCreateActionView();
|
||||
|
||||
/**
|
||||
* Performs an optional default action.
|
||||
* <p>
|
||||
* For the case of an action provider placed in a menu item not shown as an action this
|
||||
* method is invoked if previous callbacks for processing menu selection has handled
|
||||
* the event.
|
||||
* </p>
|
||||
* <p>
|
||||
* A menu item selection is processed in the following order:
|
||||
* <ul>
|
||||
* <li>
|
||||
* Receiving a call to {@link MenuItem.OnMenuItemClickListener#onMenuItemClick
|
||||
* MenuItem.OnMenuItemClickListener.onMenuItemClick}.
|
||||
* </li>
|
||||
* <li>
|
||||
* Receiving a call to {@link android.app.Activity#onOptionsItemSelected(MenuItem)
|
||||
* Activity.onOptionsItemSelected(MenuItem)}
|
||||
* </li>
|
||||
* <li>
|
||||
* Receiving a call to {@link android.app.Fragment#onOptionsItemSelected(MenuItem)
|
||||
* Fragment.onOptionsItemSelected(MenuItem)}
|
||||
* </li>
|
||||
* <li>
|
||||
* Launching the {@link android.content.Intent} set via
|
||||
* {@link MenuItem#setIntent(android.content.Intent) MenuItem.setIntent(android.content.Intent)}
|
||||
* </li>
|
||||
* <li>
|
||||
* Invoking this method.
|
||||
* </li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <p>
|
||||
* The default implementation does not perform any action and returns false.
|
||||
* </p>
|
||||
*/
|
||||
public boolean onPerformDefaultAction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this ActionProvider has a submenu associated with it.
|
||||
*
|
||||
* <p>Associated submenus will be shown when an action view is not. This
|
||||
* provider instance will receive a call to {@link #onPrepareSubMenu(SubMenu)}
|
||||
* after the call to {@link #onPerformDefaultAction()} and before a submenu is
|
||||
* displayed to the user.
|
||||
*
|
||||
* @return true if the item backed by this provider should have an associated submenu
|
||||
*/
|
||||
public boolean hasSubMenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to prepare an associated submenu for the menu item backed by this ActionProvider.
|
||||
*
|
||||
* <p>if {@link #hasSubMenu()} returns true, this method will be called when the
|
||||
* menu item is selected to prepare the submenu for presentation to the user. Apps
|
||||
* may use this to create or alter submenu content right before display.
|
||||
*
|
||||
* @param subMenu Submenu that will be displayed
|
||||
*/
|
||||
public void onPrepareSubMenu(SubMenu subMenu) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the system that the visibility of an action view's sub-UI such as
|
||||
* an anchored popup has changed. This will affect how other system
|
||||
* visibility notifications occur.
|
||||
*
|
||||
* @hide Pending future API approval
|
||||
*/
|
||||
public void subUiVisibilityChanged(boolean isVisible) {
|
||||
if (mSubUiVisibilityListener != null) {
|
||||
mSubUiVisibilityListener.onSubUiVisibilityChanged(isVisible);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide Internal use only
|
||||
*/
|
||||
public void setSubUiVisibilityListener(SubUiVisibilityListener listener) {
|
||||
mSubUiVisibilityListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide Internal use only
|
||||
*/
|
||||
public interface SubUiVisibilityListener {
|
||||
public void onSubUiVisibilityChanged(boolean isVisible);
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 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.actionbarsherlock.view;
|
||||
|
||||
/**
|
||||
* When a {@link View} implements this interface it will receive callbacks
|
||||
* when expanded or collapsed as an action view alongside the optional,
|
||||
* app-specified callbacks to {@link OnActionExpandListener}.
|
||||
*
|
||||
* <p>See {@link MenuItem} for more information about action views.
|
||||
* See {@link android.app.ActionBar} for more information about the action bar.
|
||||
*/
|
||||
public interface CollapsibleActionView {
|
||||
/**
|
||||
* Called when this view is expanded as an action view.
|
||||
* See {@link MenuItem#expandActionView()}.
|
||||
*/
|
||||
public void onActionViewExpanded();
|
||||
|
||||
/**
|
||||
* Called when this view is collapsed as an action view.
|
||||
* See {@link MenuItem#collapseActionView()}.
|
||||
*/
|
||||
public void onActionViewCollapsed();
|
||||
}
|
@ -1,447 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.actionbarsherlock.view;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
/**
|
||||
* Interface for managing the items in a menu.
|
||||
* <p>
|
||||
* By default, every Activity supports an options menu of actions or options.
|
||||
* You can add items to this menu and handle clicks on your additions. The
|
||||
* easiest way of adding menu items is inflating an XML file into the
|
||||
* {@link Menu} via {@link MenuInflater}. The easiest way of attaching code to
|
||||
* clicks is via {@link Activity#onOptionsItemSelected(MenuItem)} and
|
||||
* {@link Activity#onContextItemSelected(MenuItem)}.
|
||||
* <p>
|
||||
* Different menu types support different features:
|
||||
* <ol>
|
||||
* <li><b>Context menus</b>: Do not support item shortcuts and item icons.
|
||||
* <li><b>Options menus</b>: The <b>icon menus</b> do not support item check
|
||||
* marks and only show the item's
|
||||
* {@link MenuItem#setTitleCondensed(CharSequence) condensed title}. The
|
||||
* <b>expanded menus</b> (only available if six or more menu items are visible,
|
||||
* reached via the 'More' item in the icon menu) do not show item icons, and
|
||||
* item check marks are discouraged.
|
||||
* <li><b>Sub menus</b>: Do not support item icons, or nested sub menus.
|
||||
* </ol>
|
||||
*
|
||||
* <div class="special reference">
|
||||
* <h3>Developer Guides</h3>
|
||||
* <p>For more information about creating menus, read the
|
||||
* <a href="{@docRoot}guide/topics/ui/menus.html">Menus</a> developer guide.</p>
|
||||
* </div>
|
||||
*/
|
||||
public interface Menu {
|
||||
|
||||
/**
|
||||
* This is the part of an order integer that the user can provide.
|
||||
* @hide
|
||||
*/
|
||||
static final int USER_MASK = 0x0000ffff;
|
||||
/**
|
||||
* Bit shift of the user portion of the order integer.
|
||||
* @hide
|
||||
*/
|
||||
static final int USER_SHIFT = 0;
|
||||
|
||||
/**
|
||||
* This is the part of an order integer that supplies the category of the
|
||||
* item.
|
||||
* @hide
|
||||
*/
|
||||
static final int CATEGORY_MASK = 0xffff0000;
|
||||
/**
|
||||
* Bit shift of the category portion of the order integer.
|
||||
* @hide
|
||||
*/
|
||||
static final int CATEGORY_SHIFT = 16;
|
||||
|
||||
/**
|
||||
* Value to use for group and item identifier integers when you don't care
|
||||
* about them.
|
||||
*/
|
||||
static final int NONE = 0;
|
||||
|
||||
/**
|
||||
* First value for group and item identifier integers.
|
||||
*/
|
||||
static final int FIRST = 1;
|
||||
|
||||
// Implementation note: Keep these CATEGORY_* in sync with the category enum
|
||||
// in attrs.xml
|
||||
|
||||
/**
|
||||
* Category code for the order integer for items/groups that are part of a
|
||||
* container -- or/add this with your base value.
|
||||
*/
|
||||
static final int CATEGORY_CONTAINER = 0x00010000;
|
||||
|
||||
/**
|
||||
* Category code for the order integer for items/groups that are provided by
|
||||
* the system -- or/add this with your base value.
|
||||
*/
|
||||
static final int CATEGORY_SYSTEM = 0x00020000;
|
||||
|
||||
/**
|
||||
* Category code for the order integer for items/groups that are
|
||||
* user-supplied secondary (infrequently used) options -- or/add this with
|
||||
* your base value.
|
||||
*/
|
||||
static final int CATEGORY_SECONDARY = 0x00030000;
|
||||
|
||||
/**
|
||||
* Category code for the order integer for items/groups that are
|
||||
* alternative actions on the data that is currently displayed -- or/add
|
||||
* this with your base value.
|
||||
*/
|
||||
static final int CATEGORY_ALTERNATIVE = 0x00040000;
|
||||
|
||||
/**
|
||||
* Flag for {@link #addIntentOptions}: if set, do not automatically remove
|
||||
* any existing menu items in the same group.
|
||||
*/
|
||||
static final int FLAG_APPEND_TO_GROUP = 0x0001;
|
||||
|
||||
/**
|
||||
* Flag for {@link #performShortcut}: if set, do not close the menu after
|
||||
* executing the shortcut.
|
||||
*/
|
||||
static final int FLAG_PERFORM_NO_CLOSE = 0x0001;
|
||||
|
||||
/**
|
||||
* Flag for {@link #performShortcut(int, KeyEvent, int)}: if set, always
|
||||
* close the menu after executing the shortcut. Closing the menu also resets
|
||||
* the prepared state.
|
||||
*/
|
||||
static final int FLAG_ALWAYS_PERFORM_CLOSE = 0x0002;
|
||||
|
||||
/**
|
||||
* Add a new item to the menu. This item displays the given title for its
|
||||
* label.
|
||||
*
|
||||
* @param title The text to display for the item.
|
||||
* @return The newly added menu item.
|
||||
*/
|
||||
public MenuItem add(CharSequence title);
|
||||
|
||||
/**
|
||||
* Add a new item to the menu. This item displays the given title for its
|
||||
* label.
|
||||
*
|
||||
* @param titleRes Resource identifier of title string.
|
||||
* @return The newly added menu item.
|
||||
*/
|
||||
public MenuItem add(int titleRes);
|
||||
|
||||
/**
|
||||
* Add a new item to the menu. This item displays the given title for its
|
||||
* label.
|
||||
*
|
||||
* @param groupId The group identifier that this item should be part of.
|
||||
* This can be used to define groups of items for batch state
|
||||
* changes. Normally use {@link #NONE} if an item should not be in a
|
||||
* group.
|
||||
* @param itemId Unique item ID. Use {@link #NONE} if you do not need a
|
||||
* unique ID.
|
||||
* @param order The order for the item. Use {@link #NONE} if you do not care
|
||||
* about the order. See {@link MenuItem#getOrder()}.
|
||||
* @param title The text to display for the item.
|
||||
* @return The newly added menu item.
|
||||
*/
|
||||
public MenuItem add(int groupId, int itemId, int order, CharSequence title);
|
||||
|
||||
/**
|
||||
* Variation on {@link #add(int, int, int, CharSequence)} that takes a
|
||||
* string resource identifier instead of the string itself.
|
||||
*
|
||||
* @param groupId The group identifier that this item should be part of.
|
||||
* This can also be used to define groups of items for batch state
|
||||
* changes. Normally use {@link #NONE} if an item should not be in a
|
||||
* group.
|
||||
* @param itemId Unique item ID. Use {@link #NONE} if you do not need a
|
||||
* unique ID.
|
||||
* @param order The order for the item. Use {@link #NONE} if you do not care
|
||||
* about the order. See {@link MenuItem#getOrder()}.
|
||||
* @param titleRes Resource identifier of title string.
|
||||
* @return The newly added menu item.
|
||||
*/
|
||||
public MenuItem add(int groupId, int itemId, int order, int titleRes);
|
||||
|
||||
/**
|
||||
* Add a new sub-menu to the menu. This item displays the given title for
|
||||
* its label. To modify other attributes on the submenu's menu item, use
|
||||
* {@link SubMenu#getItem()}.
|
||||
*
|
||||
* @param title The text to display for the item.
|
||||
* @return The newly added sub-menu
|
||||
*/
|
||||
SubMenu addSubMenu(final CharSequence title);
|
||||
|
||||
/**
|
||||
* Add a new sub-menu to the menu. This item displays the given title for
|
||||
* its label. To modify other attributes on the submenu's menu item, use
|
||||
* {@link SubMenu#getItem()}.
|
||||
*
|
||||
* @param titleRes Resource identifier of title string.
|
||||
* @return The newly added sub-menu
|
||||
*/
|
||||
SubMenu addSubMenu(final int titleRes);
|
||||
|
||||
/**
|
||||
* Add a new sub-menu to the menu. This item displays the given
|
||||
* <var>title</var> for its label. To modify other attributes on the
|
||||
* submenu's menu item, use {@link SubMenu#getItem()}.
|
||||
*<p>
|
||||
* Note that you can only have one level of sub-menus, i.e. you cannnot add
|
||||
* a subMenu to a subMenu: An {@link UnsupportedOperationException} will be
|
||||
* thrown if you try.
|
||||
*
|
||||
* @param groupId The group identifier that this item should be part of.
|
||||
* This can also be used to define groups of items for batch state
|
||||
* changes. Normally use {@link #NONE} if an item should not be in a
|
||||
* group.
|
||||
* @param itemId Unique item ID. Use {@link #NONE} if you do not need a
|
||||
* unique ID.
|
||||
* @param order The order for the item. Use {@link #NONE} if you do not care
|
||||
* about the order. See {@link MenuItem#getOrder()}.
|
||||
* @param title The text to display for the item.
|
||||
* @return The newly added sub-menu
|
||||
*/
|
||||
SubMenu addSubMenu(final int groupId, final int itemId, int order, final CharSequence title);
|
||||
|
||||
/**
|
||||
* Variation on {@link #addSubMenu(int, int, int, CharSequence)} that takes
|
||||
* a string resource identifier for the title instead of the string itself.
|
||||
*
|
||||
* @param groupId The group identifier that this item should be part of.
|
||||
* This can also be used to define groups of items for batch state
|
||||
* changes. Normally use {@link #NONE} if an item should not be in a group.
|
||||
* @param itemId Unique item ID. Use {@link #NONE} if you do not need a unique ID.
|
||||
* @param order The order for the item. Use {@link #NONE} if you do not care about the
|
||||
* order. See {@link MenuItem#getOrder()}.
|
||||
* @param titleRes Resource identifier of title string.
|
||||
* @return The newly added sub-menu
|
||||
*/
|
||||
SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes);
|
||||
|
||||
/**
|
||||
* Add a group of menu items corresponding to actions that can be performed
|
||||
* for a particular Intent. The Intent is most often configured with a null
|
||||
* action, the data that the current activity is working with, and includes
|
||||
* either the {@link Intent#CATEGORY_ALTERNATIVE} or
|
||||
* {@link Intent#CATEGORY_SELECTED_ALTERNATIVE} to find activities that have
|
||||
* said they would like to be included as optional action. You can, however,
|
||||
* use any Intent you want.
|
||||
*
|
||||
* <p>
|
||||
* See {@link android.content.pm.PackageManager#queryIntentActivityOptions}
|
||||
* for more * details on the <var>caller</var>, <var>specifics</var>, and
|
||||
* <var>intent</var> arguments. The list returned by that function is used
|
||||
* to populate the resulting menu items.
|
||||
*
|
||||
* <p>
|
||||
* All of the menu items of possible options for the intent will be added
|
||||
* with the given group and id. You can use the group to control ordering of
|
||||
* the items in relation to other items in the menu. Normally this function
|
||||
* will automatically remove any existing items in the menu in the same
|
||||
* group and place a divider above and below the added items; this behavior
|
||||
* can be modified with the <var>flags</var> parameter. For each of the
|
||||
* generated items {@link MenuItem#setIntent} is called to associate the
|
||||
* appropriate Intent with the item; this means the activity will
|
||||
* automatically be started for you without having to do anything else.
|
||||
*
|
||||
* @param groupId The group identifier that the items should be part of.
|
||||
* This can also be used to define groups of items for batch state
|
||||
* changes. Normally use {@link #NONE} if the items should not be in
|
||||
* a group.
|
||||
* @param itemId Unique item ID. Use {@link #NONE} if you do not need a
|
||||
* unique ID.
|
||||
* @param order The order for the items. Use {@link #NONE} if you do not
|
||||
* care about the order. See {@link MenuItem#getOrder()}.
|
||||
* @param caller The current activity component name as defined by
|
||||
* queryIntentActivityOptions().
|
||||
* @param specifics Specific items to place first as defined by
|
||||
* queryIntentActivityOptions().
|
||||
* @param intent Intent describing the kinds of items to populate in the
|
||||
* list as defined by queryIntentActivityOptions().
|
||||
* @param flags Additional options controlling how the items are added.
|
||||
* @param outSpecificItems Optional array in which to place the menu items
|
||||
* that were generated for each of the <var>specifics</var> that were
|
||||
* requested. Entries may be null if no activity was found for that
|
||||
* specific action.
|
||||
* @return The number of menu items that were added.
|
||||
*
|
||||
* @see #FLAG_APPEND_TO_GROUP
|
||||
* @see MenuItem#setIntent
|
||||
* @see android.content.pm.PackageManager#queryIntentActivityOptions
|
||||
*/
|
||||
public int addIntentOptions(int groupId, int itemId, int order,
|
||||
ComponentName caller, Intent[] specifics,
|
||||
Intent intent, int flags, MenuItem[] outSpecificItems);
|
||||
|
||||
/**
|
||||
* Remove the item with the given identifier.
|
||||
*
|
||||
* @param id The item to be removed. If there is no item with this
|
||||
* identifier, nothing happens.
|
||||
*/
|
||||
public void removeItem(int id);
|
||||
|
||||
/**
|
||||
* Remove all items in the given group.
|
||||
*
|
||||
* @param groupId The group to be removed. If there are no items in this
|
||||
* group, nothing happens.
|
||||
*/
|
||||
public void removeGroup(int groupId);
|
||||
|
||||
/**
|
||||
* Remove all existing items from the menu, leaving it empty as if it had
|
||||
* just been created.
|
||||
*/
|
||||
public void clear();
|
||||
|
||||
/**
|
||||
* Control whether a particular group of items can show a check mark. This
|
||||
* is similar to calling {@link MenuItem#setCheckable} on all of the menu items
|
||||
* with the given group identifier, but in addition you can control whether
|
||||
* this group contains a mutually-exclusive set items. This should be called
|
||||
* after the items of the group have been added to the menu.
|
||||
*
|
||||
* @param group The group of items to operate on.
|
||||
* @param checkable Set to true to allow a check mark, false to
|
||||
* disallow. The default is false.
|
||||
* @param exclusive If set to true, only one item in this group can be
|
||||
* checked at a time; checking an item will automatically
|
||||
* uncheck all others in the group. If set to false, each
|
||||
* item can be checked independently of the others.
|
||||
*
|
||||
* @see MenuItem#setCheckable
|
||||
* @see MenuItem#setChecked
|
||||
*/
|
||||
public void setGroupCheckable(int group, boolean checkable, boolean exclusive);
|
||||
|
||||
/**
|
||||
* Show or hide all menu items that are in the given group.
|
||||
*
|
||||
* @param group The group of items to operate on.
|
||||
* @param visible If true the items are visible, else they are hidden.
|
||||
*
|
||||
* @see MenuItem#setVisible
|
||||
*/
|
||||
public void setGroupVisible(int group, boolean visible);
|
||||
|
||||
/**
|
||||
* Enable or disable all menu items that are in the given group.
|
||||
*
|
||||
* @param group The group of items to operate on.
|
||||
* @param enabled If true the items will be enabled, else they will be disabled.
|
||||
*
|
||||
* @see MenuItem#setEnabled
|
||||
*/
|
||||
public void setGroupEnabled(int group, boolean enabled);
|
||||
|
||||
/**
|
||||
* Return whether the menu currently has item items that are visible.
|
||||
*
|
||||
* @return True if there is one or more item visible,
|
||||
* else false.
|
||||
*/
|
||||
public boolean hasVisibleItems();
|
||||
|
||||
/**
|
||||
* Return the menu item with a particular identifier.
|
||||
*
|
||||
* @param id The identifier to find.
|
||||
*
|
||||
* @return The menu item object, or null if there is no item with
|
||||
* this identifier.
|
||||
*/
|
||||
public MenuItem findItem(int id);
|
||||
|
||||
/**
|
||||
* Get the number of items in the menu. Note that this will change any
|
||||
* times items are added or removed from the menu.
|
||||
*
|
||||
* @return The item count.
|
||||
*/
|
||||
public int size();
|
||||
|
||||
/**
|
||||
* Gets the menu item at the given index.
|
||||
*
|
||||
* @param index The index of the menu item to return.
|
||||
* @return The menu item.
|
||||
* @exception IndexOutOfBoundsException
|
||||
* when {@code index < 0 || >= size()}
|
||||
*/
|
||||
public MenuItem getItem(int index);
|
||||
|
||||
/**
|
||||
* Closes the menu, if open.
|
||||
*/
|
||||
public void close();
|
||||
|
||||
/**
|
||||
* Execute the menu item action associated with the given shortcut
|
||||
* character.
|
||||
*
|
||||
* @param keyCode The keycode of the shortcut key.
|
||||
* @param event Key event message.
|
||||
* @param flags Additional option flags or 0.
|
||||
*
|
||||
* @return If the given shortcut exists and is shown, returns
|
||||
* true; else returns false.
|
||||
*
|
||||
* @see #FLAG_PERFORM_NO_CLOSE
|
||||
*/
|
||||
public boolean performShortcut(int keyCode, KeyEvent event, int flags);
|
||||
|
||||
/**
|
||||
* Is a keypress one of the defined shortcut keys for this window.
|
||||
* @param keyCode the key code from {@link KeyEvent} to check.
|
||||
* @param event the {@link KeyEvent} to use to help check.
|
||||
*/
|
||||
boolean isShortcutKey(int keyCode, KeyEvent event);
|
||||
|
||||
/**
|
||||
* Execute the menu item action associated with the given menu identifier.
|
||||
*
|
||||
* @param id Identifier associated with the menu item.
|
||||
* @param flags Additional option flags or 0.
|
||||
*
|
||||
* @return If the given identifier exists and is shown, returns
|
||||
* true; else returns false.
|
||||
*
|
||||
* @see #FLAG_PERFORM_NO_CLOSE
|
||||
*/
|
||||
public boolean performIdentifierAction(int id, int flags);
|
||||
|
||||
|
||||
/**
|
||||
* Control whether the menu should be running in qwerty mode (alphabetic
|
||||
* shortcuts) or 12-key mode (numeric shortcuts).
|
||||
*
|
||||
* @param isQwerty If true the menu will use alphabetic shortcuts; else it
|
||||
* will use numeric shortcuts.
|
||||
*/
|
||||
public void setQwertyMode(boolean isQwerty);
|
||||
}
|
||||
|
@ -1,495 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
* 2011 Jake Wharton
|
||||
*
|
||||
* 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.actionbarsherlock.view;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.util.Xml;
|
||||
import android.view.InflateException;
|
||||
import android.view.View;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuItemImpl;
|
||||
|
||||
/**
|
||||
* This class is used to instantiate menu XML files into Menu objects.
|
||||
* <p>
|
||||
* For performance reasons, menu inflation relies heavily on pre-processing of
|
||||
* XML files that is done at build time. Therefore, it is not currently possible
|
||||
* to use MenuInflater with an XmlPullParser over a plain XML file at runtime;
|
||||
* it only works with an XmlPullParser returned from a compiled resource (R.
|
||||
* <em>something</em> file.)
|
||||
*/
|
||||
public class MenuInflater {
|
||||
private static final String LOG_TAG = "MenuInflater";
|
||||
|
||||
/** Menu tag name in XML. */
|
||||
private static final String XML_MENU = "menu";
|
||||
|
||||
/** Group tag name in XML. */
|
||||
private static final String XML_GROUP = "group";
|
||||
|
||||
/** Item tag name in XML. */
|
||||
private static final String XML_ITEM = "item";
|
||||
|
||||
private static final int NO_ID = 0;
|
||||
|
||||
private static final Class<?>[] ACTION_VIEW_CONSTRUCTOR_SIGNATURE = new Class[] {Context.class};
|
||||
|
||||
private static final Class<?>[] ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE = ACTION_VIEW_CONSTRUCTOR_SIGNATURE;
|
||||
|
||||
private final Object[] mActionViewConstructorArguments;
|
||||
|
||||
private final Object[] mActionProviderConstructorArguments;
|
||||
|
||||
private Context mContext;
|
||||
private Object mRealOwner;
|
||||
|
||||
/**
|
||||
* Constructs a menu inflater.
|
||||
*
|
||||
* @see Activity#getMenuInflater()
|
||||
*/
|
||||
public MenuInflater(Context context) {
|
||||
mContext = context;
|
||||
mRealOwner = context;
|
||||
mActionViewConstructorArguments = new Object[] {context};
|
||||
mActionProviderConstructorArguments = mActionViewConstructorArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a menu inflater.
|
||||
*
|
||||
* @see Activity#getMenuInflater()
|
||||
* @hide
|
||||
*/
|
||||
public MenuInflater(Context context, Object realOwner) {
|
||||
mContext = context;
|
||||
mRealOwner = realOwner;
|
||||
mActionViewConstructorArguments = new Object[] {context};
|
||||
mActionProviderConstructorArguments = mActionViewConstructorArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inflate a menu hierarchy from the specified XML resource. Throws
|
||||
* {@link InflateException} if there is an error.
|
||||
*
|
||||
* @param menuRes Resource ID for an XML layout resource to load (e.g.,
|
||||
* <code>R.menu.main_activity</code>)
|
||||
* @param menu The Menu to inflate into. The items and submenus will be
|
||||
* added to this Menu.
|
||||
*/
|
||||
public void inflate(int menuRes, Menu menu) {
|
||||
XmlResourceParser parser = null;
|
||||
try {
|
||||
parser = mContext.getResources().getLayout(menuRes);
|
||||
AttributeSet attrs = Xml.asAttributeSet(parser);
|
||||
|
||||
parseMenu(parser, attrs, menu);
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called internally to fill the given menu. If a sub menu is seen, it will
|
||||
* call this recursively.
|
||||
*/
|
||||
private void parseMenu(XmlPullParser parser, AttributeSet attrs, Menu menu)
|
||||
throws XmlPullParserException, IOException {
|
||||
MenuState menuState = new MenuState(menu);
|
||||
|
||||
int eventType = parser.getEventType();
|
||||
String tagName;
|
||||
boolean lookingForEndOfUnknownTag = false;
|
||||
String unknownTagName = null;
|
||||
|
||||
// This loop will skip to the menu start tag
|
||||
do {
|
||||
if (eventType == XmlPullParser.START_TAG) {
|
||||
tagName = parser.getName();
|
||||
if (tagName.equals(XML_MENU)) {
|
||||
// Go to next tag
|
||||
eventType = parser.next();
|
||||
break;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Expecting menu, got " + tagName);
|
||||
}
|
||||
eventType = parser.next();
|
||||
} while (eventType != XmlPullParser.END_DOCUMENT);
|
||||
|
||||
boolean reachedEndOfMenu = false;
|
||||
while (!reachedEndOfMenu) {
|
||||
switch (eventType) {
|
||||
case XmlPullParser.START_TAG:
|
||||
if (lookingForEndOfUnknownTag) {
|
||||
break;
|
||||
}
|
||||
|
||||
tagName = parser.getName();
|
||||
if (tagName.equals(XML_GROUP)) {
|
||||
menuState.readGroup(attrs);
|
||||
} else if (tagName.equals(XML_ITEM)) {
|
||||
menuState.readItem(attrs);
|
||||
} else if (tagName.equals(XML_MENU)) {
|
||||
// A menu start tag denotes a submenu for an item
|
||||
SubMenu subMenu = menuState.addSubMenuItem();
|
||||
|
||||
// Parse the submenu into returned SubMenu
|
||||
parseMenu(parser, attrs, subMenu);
|
||||
} else {
|
||||
lookingForEndOfUnknownTag = true;
|
||||
unknownTagName = tagName;
|
||||
}
|
||||
break;
|
||||
|
||||
case XmlPullParser.END_TAG:
|
||||
tagName = parser.getName();
|
||||
if (lookingForEndOfUnknownTag && tagName.equals(unknownTagName)) {
|
||||
lookingForEndOfUnknownTag = false;
|
||||
unknownTagName = null;
|
||||
} else if (tagName.equals(XML_GROUP)) {
|
||||
menuState.resetGroup();
|
||||
} else if (tagName.equals(XML_ITEM)) {
|
||||
// Add the item if it hasn't been added (if the item was
|
||||
// a submenu, it would have been added already)
|
||||
if (!menuState.hasAddedItem()) {
|
||||
if (menuState.itemActionProvider != null &&
|
||||
menuState.itemActionProvider.hasSubMenu()) {
|
||||
menuState.addSubMenuItem();
|
||||
} else {
|
||||
menuState.addItem();
|
||||
}
|
||||
}
|
||||
} else if (tagName.equals(XML_MENU)) {
|
||||
reachedEndOfMenu = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case XmlPullParser.END_DOCUMENT:
|
||||
throw new RuntimeException("Unexpected end of document");
|
||||
}
|
||||
|
||||
eventType = parser.next();
|
||||
}
|
||||
}
|
||||
|
||||
private static class InflatedOnMenuItemClickListener
|
||||
implements MenuItem.OnMenuItemClickListener {
|
||||
private static final Class<?>[] PARAM_TYPES = new Class[] { MenuItem.class };
|
||||
|
||||
private Object mRealOwner;
|
||||
private Method mMethod;
|
||||
|
||||
public InflatedOnMenuItemClickListener(Object realOwner, String methodName) {
|
||||
mRealOwner = realOwner;
|
||||
Class<?> c = realOwner.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(mRealOwner, item);
|
||||
} else {
|
||||
mMethod.invoke(mRealOwner, item);
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* State for the current menu.
|
||||
* <p>
|
||||
* Groups can not be nested unless there is another menu (which will have
|
||||
* its state class).
|
||||
*/
|
||||
private class MenuState {
|
||||
private Menu menu;
|
||||
|
||||
/*
|
||||
* Group state is set on items as they are added, allowing an item to
|
||||
* override its group state. (As opposed to set on items at the group end tag.)
|
||||
*/
|
||||
private int groupId;
|
||||
private int groupCategory;
|
||||
private int groupOrder;
|
||||
private int groupCheckable;
|
||||
private boolean groupVisible;
|
||||
private boolean groupEnabled;
|
||||
|
||||
private boolean itemAdded;
|
||||
private int itemId;
|
||||
private int itemCategoryOrder;
|
||||
private CharSequence itemTitle;
|
||||
private CharSequence itemTitleCondensed;
|
||||
private int itemIconResId;
|
||||
private char itemAlphabeticShortcut;
|
||||
private char itemNumericShortcut;
|
||||
/**
|
||||
* Sync to attrs.xml enum:
|
||||
* - 0: none
|
||||
* - 1: all
|
||||
* - 2: exclusive
|
||||
*/
|
||||
private int itemCheckable;
|
||||
private boolean itemChecked;
|
||||
private boolean itemVisible;
|
||||
private boolean itemEnabled;
|
||||
|
||||
/**
|
||||
* Sync to attrs.xml enum, values in MenuItem:
|
||||
* - 0: never
|
||||
* - 1: ifRoom
|
||||
* - 2: always
|
||||
* - -1: Safe sentinel for "no value".
|
||||
*/
|
||||
private int itemShowAsAction;
|
||||
|
||||
private int itemActionViewLayout;
|
||||
private String itemActionViewClassName;
|
||||
private String itemActionProviderClassName;
|
||||
|
||||
private String itemListenerMethodName;
|
||||
|
||||
private ActionProvider itemActionProvider;
|
||||
|
||||
private static final int defaultGroupId = NO_ID;
|
||||
private static final int defaultItemId = NO_ID;
|
||||
private static final int defaultItemCategory = 0;
|
||||
private static final int defaultItemOrder = 0;
|
||||
private static final int defaultItemCheckable = 0;
|
||||
private static final boolean defaultItemChecked = false;
|
||||
private static final boolean defaultItemVisible = true;
|
||||
private static final boolean defaultItemEnabled = true;
|
||||
|
||||
public MenuState(final Menu menu) {
|
||||
this.menu = menu;
|
||||
|
||||
resetGroup();
|
||||
}
|
||||
|
||||
public void resetGroup() {
|
||||
groupId = defaultGroupId;
|
||||
groupCategory = defaultItemCategory;
|
||||
groupOrder = defaultItemOrder;
|
||||
groupCheckable = defaultItemCheckable;
|
||||
groupVisible = defaultItemVisible;
|
||||
groupEnabled = defaultItemEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the parser is pointing to a group tag.
|
||||
*/
|
||||
public void readGroup(AttributeSet attrs) {
|
||||
TypedArray a = mContext.obtainStyledAttributes(attrs,
|
||||
R.styleable.SherlockMenuGroup);
|
||||
|
||||
groupId = a.getResourceId(R.styleable.SherlockMenuGroup_android_id, defaultGroupId);
|
||||
groupCategory = a.getInt(R.styleable.SherlockMenuGroup_android_menuCategory, defaultItemCategory);
|
||||
groupOrder = a.getInt(R.styleable.SherlockMenuGroup_android_orderInCategory, defaultItemOrder);
|
||||
groupCheckable = a.getInt(R.styleable.SherlockMenuGroup_android_checkableBehavior, defaultItemCheckable);
|
||||
groupVisible = a.getBoolean(R.styleable.SherlockMenuGroup_android_visible, defaultItemVisible);
|
||||
groupEnabled = a.getBoolean(R.styleable.SherlockMenuGroup_android_enabled, defaultItemEnabled);
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the parser is pointing to an item tag.
|
||||
*/
|
||||
public void readItem(AttributeSet attrs) {
|
||||
TypedArray a = mContext.obtainStyledAttributes(attrs,
|
||||
R.styleable.SherlockMenuItem);
|
||||
|
||||
// Inherit attributes from the group as default value
|
||||
itemId = a.getResourceId(R.styleable.SherlockMenuItem_android_id, defaultItemId);
|
||||
final int category = a.getInt(R.styleable.SherlockMenuItem_android_menuCategory, groupCategory);
|
||||
final int order = a.getInt(R.styleable.SherlockMenuItem_android_orderInCategory, groupOrder);
|
||||
itemCategoryOrder = (category & Menu.CATEGORY_MASK) | (order & Menu.USER_MASK);
|
||||
itemTitle = a.getText(R.styleable.SherlockMenuItem_android_title);
|
||||
itemTitleCondensed = a.getText(R.styleable.SherlockMenuItem_android_titleCondensed);
|
||||
itemIconResId = a.getResourceId(R.styleable.SherlockMenuItem_android_icon, 0);
|
||||
itemAlphabeticShortcut =
|
||||
getShortcut(a.getString(R.styleable.SherlockMenuItem_android_alphabeticShortcut));
|
||||
itemNumericShortcut =
|
||||
getShortcut(a.getString(R.styleable.SherlockMenuItem_android_numericShortcut));
|
||||
if (a.hasValue(R.styleable.SherlockMenuItem_android_checkable)) {
|
||||
// Item has attribute checkable, use it
|
||||
itemCheckable = a.getBoolean(R.styleable.SherlockMenuItem_android_checkable, false) ? 1 : 0;
|
||||
} else {
|
||||
// Item does not have attribute, use the group's (group can have one more state
|
||||
// for checkable that represents the exclusive checkable)
|
||||
itemCheckable = groupCheckable;
|
||||
}
|
||||
|
||||
itemChecked = a.getBoolean(R.styleable.SherlockMenuItem_android_checked, defaultItemChecked);
|
||||
itemVisible = a.getBoolean(R.styleable.SherlockMenuItem_android_visible, groupVisible);
|
||||
itemEnabled = a.getBoolean(R.styleable.SherlockMenuItem_android_enabled, groupEnabled);
|
||||
|
||||
TypedValue value = new TypedValue();
|
||||
a.getValue(R.styleable.SherlockMenuItem_android_showAsAction, value);
|
||||
itemShowAsAction = value.type == TypedValue.TYPE_INT_HEX ? value.data : -1;
|
||||
|
||||
itemListenerMethodName = a.getString(R.styleable.SherlockMenuItem_android_onClick);
|
||||
itemActionViewLayout = a.getResourceId(R.styleable.SherlockMenuItem_android_actionLayout, 0);
|
||||
|
||||
// itemActionViewClassName = a.getString(R.styleable.SherlockMenuItem_android_actionViewClass);
|
||||
value = new TypedValue();
|
||||
a.getValue(R.styleable.SherlockMenuItem_android_actionViewClass, value);
|
||||
itemActionViewClassName = value.type == TypedValue.TYPE_STRING ? value.string.toString() : null;
|
||||
|
||||
// itemActionProviderClassName = a.getString(R.styleable.SherlockMenuItem_android_actionProviderClass);
|
||||
value = new TypedValue();
|
||||
a.getValue(R.styleable.SherlockMenuItem_android_actionProviderClass, value);
|
||||
itemActionProviderClassName = value.type == TypedValue.TYPE_STRING ? value.string.toString() : null;
|
||||
|
||||
final boolean hasActionProvider = itemActionProviderClassName != null;
|
||||
if (hasActionProvider && itemActionViewLayout == 0 && itemActionViewClassName == null) {
|
||||
itemActionProvider = newInstance(itemActionProviderClassName,
|
||||
ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE,
|
||||
mActionProviderConstructorArguments);
|
||||
} else {
|
||||
if (hasActionProvider) {
|
||||
Log.w(LOG_TAG, "Ignoring attribute 'actionProviderClass'."
|
||||
+ " Action view already specified.");
|
||||
}
|
||||
itemActionProvider = null;
|
||||
}
|
||||
|
||||
a.recycle();
|
||||
|
||||
itemAdded = false;
|
||||
}
|
||||
|
||||
private char getShortcut(String shortcutString) {
|
||||
if (shortcutString == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return shortcutString.charAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void setItem(MenuItem item) {
|
||||
item.setChecked(itemChecked)
|
||||
.setVisible(itemVisible)
|
||||
.setEnabled(itemEnabled)
|
||||
.setCheckable(itemCheckable >= 1)
|
||||
.setTitleCondensed(itemTitleCondensed)
|
||||
.setIcon(itemIconResId)
|
||||
.setAlphabeticShortcut(itemAlphabeticShortcut)
|
||||
.setNumericShortcut(itemNumericShortcut);
|
||||
|
||||
if (itemShowAsAction >= 0) {
|
||||
item.setShowAsAction(itemShowAsAction);
|
||||
}
|
||||
|
||||
if (itemListenerMethodName != null) {
|
||||
if (mContext.isRestricted()) {
|
||||
throw new IllegalStateException("The android:onClick attribute cannot "
|
||||
+ "be used within a restricted context");
|
||||
}
|
||||
item.setOnMenuItemClickListener(
|
||||
new InflatedOnMenuItemClickListener(mRealOwner, itemListenerMethodName));
|
||||
}
|
||||
|
||||
if (itemCheckable >= 2) {
|
||||
if (item instanceof MenuItemImpl) {
|
||||
MenuItemImpl impl = (MenuItemImpl) item;
|
||||
impl.setExclusiveCheckable(true);
|
||||
} else {
|
||||
menu.setGroupCheckable(groupId, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
boolean actionViewSpecified = false;
|
||||
if (itemActionViewClassName != null) {
|
||||
View actionView = (View) newInstance(itemActionViewClassName,
|
||||
ACTION_VIEW_CONSTRUCTOR_SIGNATURE, mActionViewConstructorArguments);
|
||||
item.setActionView(actionView);
|
||||
actionViewSpecified = true;
|
||||
}
|
||||
if (itemActionViewLayout > 0) {
|
||||
if (!actionViewSpecified) {
|
||||
item.setActionView(itemActionViewLayout);
|
||||
actionViewSpecified = true;
|
||||
} else {
|
||||
Log.w(LOG_TAG, "Ignoring attribute 'itemActionViewLayout'."
|
||||
+ " Action view already specified.");
|
||||
}
|
||||
}
|
||||
if (itemActionProvider != null) {
|
||||
item.setActionProvider(itemActionProvider);
|
||||
}
|
||||
}
|
||||
|
||||
public void addItem() {
|
||||
itemAdded = true;
|
||||
setItem(menu.add(groupId, itemId, itemCategoryOrder, itemTitle));
|
||||
}
|
||||
|
||||
public SubMenu addSubMenuItem() {
|
||||
itemAdded = true;
|
||||
SubMenu subMenu = menu.addSubMenu(groupId, itemId, itemCategoryOrder, itemTitle);
|
||||
setItem(subMenu.getItem());
|
||||
return subMenu;
|
||||
}
|
||||
|
||||
public boolean hasAddedItem() {
|
||||
return itemAdded;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T newInstance(String className, Class<?>[] constructorSignature,
|
||||
Object[] arguments) {
|
||||
try {
|
||||
Class<?> clazz = mContext.getClassLoader().loadClass(className);
|
||||
Constructor<?> constructor = clazz.getConstructor(constructorSignature);
|
||||
return (T) constructor.newInstance(arguments);
|
||||
} catch (Exception e) {
|
||||
Log.w(LOG_TAG, "Cannot instantiate class: " + className, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,598 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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.actionbarsherlock.view;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Interface for direct access to a previously created menu item.
|
||||
* <p>
|
||||
* An Item is returned by calling one of the {@link android.view.Menu#add}
|
||||
* methods.
|
||||
* <p>
|
||||
* For a feature set of specific menu types, see {@link Menu}.
|
||||
*
|
||||
* <div class="special reference">
|
||||
* <h3>Developer Guides</h3>
|
||||
* <p>For information about creating menus, read the
|
||||
* <a href="{@docRoot}guide/topics/ui/menus.html">Menus</a> developer guide.</p>
|
||||
* </div>
|
||||
*/
|
||||
public interface MenuItem {
|
||||
/*
|
||||
* These should be kept in sync with attrs.xml enum constants for showAsAction
|
||||
*/
|
||||
/** Never show this item as a button in an Action Bar. */
|
||||
public static final int SHOW_AS_ACTION_NEVER = android.view.MenuItem.SHOW_AS_ACTION_NEVER;
|
||||
/** Show this item as a button in an Action Bar if the system decides there is room for it. */
|
||||
public static final int SHOW_AS_ACTION_IF_ROOM = android.view.MenuItem.SHOW_AS_ACTION_IF_ROOM;
|
||||
/**
|
||||
* Always show this item as a button in an Action Bar.
|
||||
* Use sparingly! If too many items are set to always show in the Action Bar it can
|
||||
* crowd the Action Bar and degrade the user experience on devices with smaller screens.
|
||||
* A good rule of thumb is to have no more than 2 items set to always show at a time.
|
||||
*/
|
||||
public static final int SHOW_AS_ACTION_ALWAYS = android.view.MenuItem.SHOW_AS_ACTION_ALWAYS;
|
||||
|
||||
/**
|
||||
* When this item is in the action bar, always show it with a text label even if
|
||||
* it also has an icon specified.
|
||||
*/
|
||||
public static final int SHOW_AS_ACTION_WITH_TEXT = android.view.MenuItem.SHOW_AS_ACTION_WITH_TEXT;
|
||||
|
||||
/**
|
||||
* This item's action view collapses to a normal menu item.
|
||||
* When expanded, the action view temporarily takes over
|
||||
* a larger segment of its container.
|
||||
*/
|
||||
public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = android.view.MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW;
|
||||
|
||||
/**
|
||||
* Interface definition for a callback to be invoked when a menu item is
|
||||
* clicked.
|
||||
*
|
||||
* @see Activity#onContextItemSelected(MenuItem)
|
||||
* @see Activity#onOptionsItemSelected(MenuItem)
|
||||
*/
|
||||
public interface OnMenuItemClickListener {
|
||||
/**
|
||||
* Called when a menu item has been invoked. This is the first code
|
||||
* that is executed; if it returns true, no other callbacks will be
|
||||
* executed.
|
||||
*
|
||||
* @param item The menu item that was invoked.
|
||||
*
|
||||
* @return Return true to consume this click and prevent others from
|
||||
* executing.
|
||||
*/
|
||||
public boolean onMenuItemClick(MenuItem item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface definition for a callback to be invoked when a menu item
|
||||
* marked with {@link MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW} is
|
||||
* expanded or collapsed.
|
||||
*
|
||||
* @see MenuItem#expandActionView()
|
||||
* @see MenuItem#collapseActionView()
|
||||
* @see MenuItem#setShowAsActionFlags(int)
|
||||
*/
|
||||
public interface OnActionExpandListener {
|
||||
/**
|
||||
* Called when a menu item with {@link MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}
|
||||
* is expanded.
|
||||
* @param item Item that was expanded
|
||||
* @return true if the item should expand, false if expansion should be suppressed.
|
||||
*/
|
||||
public boolean onMenuItemActionExpand(MenuItem item);
|
||||
|
||||
/**
|
||||
* Called when a menu item with {@link MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}
|
||||
* is collapsed.
|
||||
* @param item Item that was collapsed
|
||||
* @return true if the item should collapse, false if collapsing should be suppressed.
|
||||
*/
|
||||
public boolean onMenuItemActionCollapse(MenuItem item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the identifier for this menu item. The identifier can not
|
||||
* be changed after the menu is created.
|
||||
*
|
||||
* @return The menu item's identifier.
|
||||
*/
|
||||
public int getItemId();
|
||||
|
||||
/**
|
||||
* Return the group identifier that this menu item is part of. The group
|
||||
* identifier can not be changed after the menu is created.
|
||||
*
|
||||
* @return The menu item's group identifier.
|
||||
*/
|
||||
public int getGroupId();
|
||||
|
||||
/**
|
||||
* Return the category and order within the category of this item. This
|
||||
* item will be shown before all items (within its category) that have
|
||||
* order greater than this value.
|
||||
* <p>
|
||||
* An order integer contains the item's category (the upper bits of the
|
||||
* integer; set by or/add the category with the order within the
|
||||
* category) and the ordering of the item within that category (the
|
||||
* lower bits). Example categories are {@link Menu#CATEGORY_SYSTEM},
|
||||
* {@link Menu#CATEGORY_SECONDARY}, {@link Menu#CATEGORY_ALTERNATIVE},
|
||||
* {@link Menu#CATEGORY_CONTAINER}. See {@link Menu} for a full list.
|
||||
*
|
||||
* @return The order of this item.
|
||||
*/
|
||||
public int getOrder();
|
||||
|
||||
/**
|
||||
* Change the title associated with this item.
|
||||
*
|
||||
* @param title The new text to be displayed.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setTitle(CharSequence title);
|
||||
|
||||
/**
|
||||
* Change the title associated with this item.
|
||||
* <p>
|
||||
* Some menu types do not sufficient space to show the full title, and
|
||||
* instead a condensed title is preferred. See {@link Menu} for more
|
||||
* information.
|
||||
*
|
||||
* @param title The resource id of the new text to be displayed.
|
||||
* @return This Item so additional setters can be called.
|
||||
* @see #setTitleCondensed(CharSequence)
|
||||
*/
|
||||
|
||||
public MenuItem setTitle(int title);
|
||||
|
||||
/**
|
||||
* Retrieve the current title of the item.
|
||||
*
|
||||
* @return The title.
|
||||
*/
|
||||
public CharSequence getTitle();
|
||||
|
||||
/**
|
||||
* Change the condensed title associated with this item. The condensed
|
||||
* title is used in situations where the normal title may be too long to
|
||||
* be displayed.
|
||||
*
|
||||
* @param title The new text to be displayed as the condensed title.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setTitleCondensed(CharSequence title);
|
||||
|
||||
/**
|
||||
* Retrieve the current condensed title of the item. If a condensed
|
||||
* title was never set, it will return the normal title.
|
||||
*
|
||||
* @return The condensed title, if it exists.
|
||||
* Otherwise the normal title.
|
||||
*/
|
||||
public CharSequence getTitleCondensed();
|
||||
|
||||
/**
|
||||
* Change the icon associated with this item. This icon will not always be
|
||||
* shown, so the title should be sufficient in describing this item. See
|
||||
* {@link Menu} for the menu types that support icons.
|
||||
*
|
||||
* @param icon The new icon (as a Drawable) to be displayed.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setIcon(Drawable icon);
|
||||
|
||||
/**
|
||||
* Change the icon associated with this item. This icon will not always be
|
||||
* shown, so the title should be sufficient in describing this item. See
|
||||
* {@link Menu} for the menu types that support icons.
|
||||
* <p>
|
||||
* This method will set the resource ID of the icon which will be used to
|
||||
* lazily get the Drawable when this item is being shown.
|
||||
*
|
||||
* @param iconRes The new icon (as a resource ID) to be displayed.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setIcon(int iconRes);
|
||||
|
||||
/**
|
||||
* Returns the icon for this item as a Drawable (getting it from resources if it hasn't been
|
||||
* loaded before).
|
||||
*
|
||||
* @return The icon as a Drawable.
|
||||
*/
|
||||
public Drawable getIcon();
|
||||
|
||||
/**
|
||||
* Change the Intent associated with this item. By default there is no
|
||||
* Intent associated with a menu item. If you set one, and nothing
|
||||
* else handles the item, then the default behavior will be to call
|
||||
* {@link android.content.Context#startActivity} with the given Intent.
|
||||
*
|
||||
* <p>Note that setIntent() can not be used with the versions of
|
||||
* {@link Menu#add} that take a Runnable, because {@link Runnable#run}
|
||||
* does not return a value so there is no way to tell if it handled the
|
||||
* item. In this case it is assumed that the Runnable always handles
|
||||
* the item, and the intent will never be started.
|
||||
*
|
||||
* @see #getIntent
|
||||
* @param intent The Intent to associated with the item. This Intent
|
||||
* object is <em>not</em> copied, so be careful not to
|
||||
* modify it later.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setIntent(Intent intent);
|
||||
|
||||
/**
|
||||
* Return the Intent associated with this item. This returns a
|
||||
* reference to the Intent which you can change as desired to modify
|
||||
* what the Item is holding.
|
||||
*
|
||||
* @see #setIntent
|
||||
* @return Returns the last value supplied to {@link #setIntent}, or
|
||||
* null.
|
||||
*/
|
||||
public Intent getIntent();
|
||||
|
||||
/**
|
||||
* Change both the numeric and alphabetic shortcut associated with this
|
||||
* item. Note that the shortcut will be triggered when the key that
|
||||
* generates the given character is pressed alone or along with with the alt
|
||||
* key. Also note that case is not significant and that alphabetic shortcut
|
||||
* characters will be displayed in lower case.
|
||||
* <p>
|
||||
* See {@link Menu} for the menu types that support shortcuts.
|
||||
*
|
||||
* @param numericChar The numeric shortcut key. This is the shortcut when
|
||||
* using a numeric (e.g., 12-key) keyboard.
|
||||
* @param alphaChar The alphabetic shortcut key. This is the shortcut when
|
||||
* using a keyboard with alphabetic keys.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setShortcut(char numericChar, char alphaChar);
|
||||
|
||||
/**
|
||||
* Change the numeric shortcut associated with this item.
|
||||
* <p>
|
||||
* See {@link Menu} for the menu types that support shortcuts.
|
||||
*
|
||||
* @param numericChar The numeric shortcut key. This is the shortcut when
|
||||
* using a 12-key (numeric) keyboard.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setNumericShortcut(char numericChar);
|
||||
|
||||
/**
|
||||
* Return the char for this menu item's numeric (12-key) shortcut.
|
||||
*
|
||||
* @return Numeric character to use as a shortcut.
|
||||
*/
|
||||
public char getNumericShortcut();
|
||||
|
||||
/**
|
||||
* Change the alphabetic shortcut associated with this item. The shortcut
|
||||
* will be triggered when the key that generates the given character is
|
||||
* pressed alone or along with with the alt key. Case is not significant and
|
||||
* shortcut characters will be displayed in lower case. Note that menu items
|
||||
* with the characters '\b' or '\n' as shortcuts will get triggered by the
|
||||
* Delete key or Carriage Return key, respectively.
|
||||
* <p>
|
||||
* See {@link Menu} for the menu types that support shortcuts.
|
||||
*
|
||||
* @param alphaChar The alphabetic shortcut key. This is the shortcut when
|
||||
* using a keyboard with alphabetic keys.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setAlphabeticShortcut(char alphaChar);
|
||||
|
||||
/**
|
||||
* Return the char for this menu item's alphabetic shortcut.
|
||||
*
|
||||
* @return Alphabetic character to use as a shortcut.
|
||||
*/
|
||||
public char getAlphabeticShortcut();
|
||||
|
||||
/**
|
||||
* Control whether this item can display a check mark. Setting this does
|
||||
* not actually display a check mark (see {@link #setChecked} for that);
|
||||
* rather, it ensures there is room in the item in which to display a
|
||||
* check mark.
|
||||
* <p>
|
||||
* See {@link Menu} for the menu types that support check marks.
|
||||
*
|
||||
* @param checkable Set to true to allow a check mark, false to
|
||||
* disallow. The default is false.
|
||||
* @see #setChecked
|
||||
* @see #isCheckable
|
||||
* @see Menu#setGroupCheckable
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setCheckable(boolean checkable);
|
||||
|
||||
/**
|
||||
* Return whether the item can currently display a check mark.
|
||||
*
|
||||
* @return If a check mark can be displayed, returns true.
|
||||
*
|
||||
* @see #setCheckable
|
||||
*/
|
||||
public boolean isCheckable();
|
||||
|
||||
/**
|
||||
* Control whether this item is shown with a check mark. Note that you
|
||||
* must first have enabled checking with {@link #setCheckable} or else
|
||||
* the check mark will not appear. If this item is a member of a group that contains
|
||||
* mutually-exclusive items (set via {@link Menu#setGroupCheckable(int, boolean, boolean)},
|
||||
* the other items in the group will be unchecked.
|
||||
* <p>
|
||||
* See {@link Menu} for the menu types that support check marks.
|
||||
*
|
||||
* @see #setCheckable
|
||||
* @see #isChecked
|
||||
* @see Menu#setGroupCheckable
|
||||
* @param checked Set to true to display a check mark, false to hide
|
||||
* it. The default value is false.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setChecked(boolean checked);
|
||||
|
||||
/**
|
||||
* Return whether the item is currently displaying a check mark.
|
||||
*
|
||||
* @return If a check mark is displayed, returns true.
|
||||
*
|
||||
* @see #setChecked
|
||||
*/
|
||||
public boolean isChecked();
|
||||
|
||||
/**
|
||||
* Sets the visibility of the menu item. Even if a menu item is not visible,
|
||||
* it may still be invoked via its shortcut (to completely disable an item,
|
||||
* set it to invisible and {@link #setEnabled(boolean) disabled}).
|
||||
*
|
||||
* @param visible If true then the item will be visible; if false it is
|
||||
* hidden.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setVisible(boolean visible);
|
||||
|
||||
/**
|
||||
* Return the visibility of the menu item.
|
||||
*
|
||||
* @return If true the item is visible; else it is hidden.
|
||||
*/
|
||||
public boolean isVisible();
|
||||
|
||||
/**
|
||||
* Sets whether the menu item is enabled. Disabling a menu item will not
|
||||
* allow it to be invoked via its shortcut. The menu item will still be
|
||||
* visible.
|
||||
*
|
||||
* @param enabled If true then the item will be invokable; if false it is
|
||||
* won't be invokable.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Return the enabled state of the menu item.
|
||||
*
|
||||
* @return If true the item is enabled and hence invokable; else it is not.
|
||||
*/
|
||||
public boolean isEnabled();
|
||||
|
||||
/**
|
||||
* Check whether this item has an associated sub-menu. I.e. it is a
|
||||
* sub-menu of another menu.
|
||||
*
|
||||
* @return If true this item has a menu; else it is a
|
||||
* normal item.
|
||||
*/
|
||||
public boolean hasSubMenu();
|
||||
|
||||
/**
|
||||
* Get the sub-menu to be invoked when this item is selected, if it has
|
||||
* one. See {@link #hasSubMenu()}.
|
||||
*
|
||||
* @return The associated menu if there is one, else null
|
||||
*/
|
||||
public SubMenu getSubMenu();
|
||||
|
||||
/**
|
||||
* Set a custom listener for invocation of this menu item. In most
|
||||
* situations, it is more efficient and easier to use
|
||||
* {@link Activity#onOptionsItemSelected(MenuItem)} or
|
||||
* {@link Activity#onContextItemSelected(MenuItem)}.
|
||||
*
|
||||
* @param menuItemClickListener The object to receive invokations.
|
||||
* @return This Item so additional setters can be called.
|
||||
* @see Activity#onOptionsItemSelected(MenuItem)
|
||||
* @see Activity#onContextItemSelected(MenuItem)
|
||||
*/
|
||||
public MenuItem setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener menuItemClickListener);
|
||||
|
||||
/**
|
||||
* Gets the extra information linked to this menu item. This extra
|
||||
* information is set by the View that added this menu item to the
|
||||
* menu.
|
||||
*
|
||||
* @see OnCreateContextMenuListener
|
||||
* @return The extra information linked to the View that added this
|
||||
* menu item to the menu. This can be null.
|
||||
*/
|
||||
public ContextMenuInfo getMenuInfo();
|
||||
|
||||
/**
|
||||
* Sets how this item should display in the presence of an Action Bar.
|
||||
* The parameter actionEnum is a flag set. One of {@link #SHOW_AS_ACTION_ALWAYS},
|
||||
* {@link #SHOW_AS_ACTION_IF_ROOM}, or {@link #SHOW_AS_ACTION_NEVER} should
|
||||
* be used, and you may optionally OR the value with {@link #SHOW_AS_ACTION_WITH_TEXT}.
|
||||
* SHOW_AS_ACTION_WITH_TEXT requests that when the item is shown as an action,
|
||||
* it should be shown with a text label.
|
||||
*
|
||||
* @param actionEnum How the item should display. One of
|
||||
* {@link #SHOW_AS_ACTION_ALWAYS}, {@link #SHOW_AS_ACTION_IF_ROOM}, or
|
||||
* {@link #SHOW_AS_ACTION_NEVER}. SHOW_AS_ACTION_NEVER is the default.
|
||||
*
|
||||
* @see android.app.ActionBar
|
||||
* @see #setActionView(View)
|
||||
*/
|
||||
public void setShowAsAction(int actionEnum);
|
||||
|
||||
/**
|
||||
* Sets how this item should display in the presence of an Action Bar.
|
||||
* The parameter actionEnum is a flag set. One of {@link #SHOW_AS_ACTION_ALWAYS},
|
||||
* {@link #SHOW_AS_ACTION_IF_ROOM}, or {@link #SHOW_AS_ACTION_NEVER} should
|
||||
* be used, and you may optionally OR the value with {@link #SHOW_AS_ACTION_WITH_TEXT}.
|
||||
* SHOW_AS_ACTION_WITH_TEXT requests that when the item is shown as an action,
|
||||
* it should be shown with a text label.
|
||||
*
|
||||
* <p>Note: This method differs from {@link #setShowAsAction(int)} only in that it
|
||||
* returns the current MenuItem instance for call chaining.
|
||||
*
|
||||
* @param actionEnum How the item should display. One of
|
||||
* {@link #SHOW_AS_ACTION_ALWAYS}, {@link #SHOW_AS_ACTION_IF_ROOM}, or
|
||||
* {@link #SHOW_AS_ACTION_NEVER}. SHOW_AS_ACTION_NEVER is the default.
|
||||
*
|
||||
* @see android.app.ActionBar
|
||||
* @see #setActionView(View)
|
||||
* @return This MenuItem instance for call chaining.
|
||||
*/
|
||||
public MenuItem setShowAsActionFlags(int actionEnum);
|
||||
|
||||
/**
|
||||
* Set an action view for this menu item. An action view will be displayed in place
|
||||
* of an automatically generated menu item element in the UI when this item is shown
|
||||
* as an action within a parent.
|
||||
* <p>
|
||||
* <strong>Note:</strong> Setting an action view overrides the action provider
|
||||
* set via {@link #setActionProvider(ActionProvider)}.
|
||||
* </p>
|
||||
*
|
||||
* @param view View to use for presenting this item to the user.
|
||||
* @return This Item so additional setters can be called.
|
||||
*
|
||||
* @see #setShowAsAction(int)
|
||||
*/
|
||||
public MenuItem setActionView(View view);
|
||||
|
||||
/**
|
||||
* Set an action view for this menu item. An action view will be displayed in place
|
||||
* of an automatically generated menu item element in the UI when this item is shown
|
||||
* as an action within a parent.
|
||||
* <p>
|
||||
* <strong>Note:</strong> Setting an action view overrides the action provider
|
||||
* set via {@link #setActionProvider(ActionProvider)}.
|
||||
* </p>
|
||||
*
|
||||
* @param resId Layout resource to use for presenting this item to the user.
|
||||
* @return This Item so additional setters can be called.
|
||||
*
|
||||
* @see #setShowAsAction(int)
|
||||
*/
|
||||
public MenuItem setActionView(int resId);
|
||||
|
||||
/**
|
||||
* Returns the currently set action view for this menu item.
|
||||
*
|
||||
* @return This item's action view
|
||||
*
|
||||
* @see #setActionView(View)
|
||||
* @see #setShowAsAction(int)
|
||||
*/
|
||||
public View getActionView();
|
||||
|
||||
/**
|
||||
* Sets the {@link ActionProvider} responsible for creating an action view if
|
||||
* the item is placed on the action bar. The provider also provides a default
|
||||
* action invoked if the item is placed in the overflow menu.
|
||||
* <p>
|
||||
* <strong>Note:</strong> Setting an action provider overrides the action view
|
||||
* set via {@link #setActionView(int)} or {@link #setActionView(View)}.
|
||||
* </p>
|
||||
*
|
||||
* @param actionProvider The action provider.
|
||||
* @return This Item so additional setters can be called.
|
||||
*
|
||||
* @see ActionProvider
|
||||
*/
|
||||
public MenuItem setActionProvider(ActionProvider actionProvider);
|
||||
|
||||
/**
|
||||
* Gets the {@link ActionProvider}.
|
||||
*
|
||||
* @return The action provider.
|
||||
*
|
||||
* @see ActionProvider
|
||||
* @see #setActionProvider(ActionProvider)
|
||||
*/
|
||||
public ActionProvider getActionProvider();
|
||||
|
||||
/**
|
||||
* Expand the action view associated with this menu item.
|
||||
* The menu item must have an action view set, as well as
|
||||
* the showAsAction flag {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}.
|
||||
* If a listener has been set using {@link #setOnActionExpandListener(OnActionExpandListener)}
|
||||
* it will have its {@link OnActionExpandListener#onMenuItemActionExpand(MenuItem)}
|
||||
* method invoked. The listener may return false from this method to prevent expanding
|
||||
* the action view.
|
||||
*
|
||||
* @return true if the action view was expanded, false otherwise.
|
||||
*/
|
||||
public boolean expandActionView();
|
||||
|
||||
/**
|
||||
* Collapse the action view associated with this menu item.
|
||||
* The menu item must have an action view set, as well as the showAsAction flag
|
||||
* {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}. If a listener has been set using
|
||||
* {@link #setOnActionExpandListener(OnActionExpandListener)} it will have its
|
||||
* {@link OnActionExpandListener#onMenuItemActionCollapse(MenuItem)} method invoked.
|
||||
* The listener may return false from this method to prevent collapsing the action view.
|
||||
*
|
||||
* @return true if the action view was collapsed, false otherwise.
|
||||
*/
|
||||
public boolean collapseActionView();
|
||||
|
||||
/**
|
||||
* Returns true if this menu item's action view has been expanded.
|
||||
*
|
||||
* @return true if the item's action view is expanded, false otherwise.
|
||||
*
|
||||
* @see #expandActionView()
|
||||
* @see #collapseActionView()
|
||||
* @see #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
|
||||
* @see OnActionExpandListener
|
||||
*/
|
||||
public boolean isActionViewExpanded();
|
||||
|
||||
/**
|
||||
* Set an {@link OnActionExpandListener} on this menu item to be notified when
|
||||
* the associated action view is expanded or collapsed. The menu item must
|
||||
* be configured to expand or collapse its action view using the flag
|
||||
* {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}.
|
||||
*
|
||||
* @param listener Listener that will respond to expand/collapse events
|
||||
* @return This menu item instance for call chaining
|
||||
*/
|
||||
public MenuItem setOnActionExpandListener(OnActionExpandListener listener);
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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.actionbarsherlock.view;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Subclass of {@link Menu} for sub menus.
|
||||
* <p>
|
||||
* Sub menus do not support item icons, or nested sub menus.
|
||||
*
|
||||
* <div class="special reference">
|
||||
* <h3>Developer Guides</h3>
|
||||
* <p>For information about creating menus, read the
|
||||
* <a href="{@docRoot}guide/topics/ui/menus.html">Menus</a> developer guide.</p>
|
||||
* </div>
|
||||
*/
|
||||
|
||||
public interface SubMenu extends Menu {
|
||||
/**
|
||||
* Sets the submenu header's title to the title given in <var>titleRes</var>
|
||||
* resource identifier.
|
||||
*
|
||||
* @param titleRes The string resource identifier used for the title.
|
||||
* @return This SubMenu so additional setters can be called.
|
||||
*/
|
||||
public SubMenu setHeaderTitle(int titleRes);
|
||||
|
||||
/**
|
||||
* Sets the submenu header's title to the title given in <var>title</var>.
|
||||
*
|
||||
* @param title The character sequence used for the title.
|
||||
* @return This SubMenu so additional setters can be called.
|
||||
*/
|
||||
public SubMenu setHeaderTitle(CharSequence title);
|
||||
|
||||
/**
|
||||
* Sets the submenu header's icon to the icon given in <var>iconRes</var>
|
||||
* resource id.
|
||||
*
|
||||
* @param iconRes The resource identifier used for the icon.
|
||||
* @return This SubMenu so additional setters can be called.
|
||||
*/
|
||||
public SubMenu setHeaderIcon(int iconRes);
|
||||
|
||||
/**
|
||||
* Sets the submenu header's icon to the icon given in <var>icon</var>
|
||||
* {@link Drawable}.
|
||||
*
|
||||
* @param icon The {@link Drawable} used for the icon.
|
||||
* @return This SubMenu so additional setters can be called.
|
||||
*/
|
||||
public SubMenu setHeaderIcon(Drawable icon);
|
||||
|
||||
/**
|
||||
* Sets the header of the submenu to the {@link View} given in
|
||||
* <var>view</var>. This replaces the header title and icon (and those
|
||||
* replace this).
|
||||
*
|
||||
* @param view The {@link View} used for the header.
|
||||
* @return This SubMenu so additional setters can be called.
|
||||
*/
|
||||
public SubMenu setHeaderView(View view);
|
||||
|
||||
/**
|
||||
* Clears the header of the submenu.
|
||||
*/
|
||||
public void clearHeader();
|
||||
|
||||
/**
|
||||
* Change the icon associated with this submenu's item in its parent menu.
|
||||
*
|
||||
* @see MenuItem#setIcon(int)
|
||||
* @param iconRes The new icon (as a resource ID) to be displayed.
|
||||
* @return This SubMenu so additional setters can be called.
|
||||
*/
|
||||
public SubMenu setIcon(int iconRes);
|
||||
|
||||
/**
|
||||
* Change the icon associated with this submenu's item in its parent menu.
|
||||
*
|
||||
* @see MenuItem#setIcon(Drawable)
|
||||
* @param icon The new icon (as a Drawable) to be displayed.
|
||||
* @return This SubMenu so additional setters can be called.
|
||||
*/
|
||||
public SubMenu setIcon(Drawable icon);
|
||||
|
||||
/**
|
||||
* Gets the {@link MenuItem} that represents this submenu in the parent
|
||||
* menu. Use this for setting additional item attributes.
|
||||
*
|
||||
* @return The {@link MenuItem} that launches the submenu when invoked.
|
||||
*/
|
||||
public MenuItem getItem();
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
* Copyright (C) 2011 Jake Wharton
|
||||
*
|
||||
* 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.actionbarsherlock.view;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* <p>Abstract base class for a top-level window look and behavior policy. An
|
||||
* instance of this class should be used as the top-level view added to the
|
||||
* window manager. It provides standard UI policies such as a background, title
|
||||
* area, default key processing, etc.</p>
|
||||
*
|
||||
* <p>The only existing implementation of this abstract class is
|
||||
* android.policy.PhoneWindow, which you should instantiate when needing a
|
||||
* Window. Eventually that class will be refactored and a factory method added
|
||||
* for creating Window instances without knowing about a particular
|
||||
* implementation.</p>
|
||||
*/
|
||||
public abstract class Window extends android.view.Window {
|
||||
public static final long FEATURE_ACTION_BAR = android.view.Window.FEATURE_ACTION_BAR;
|
||||
public static final long FEATURE_ACTION_BAR_OVERLAY = android.view.Window.FEATURE_ACTION_BAR_OVERLAY;
|
||||
public static final long FEATURE_ACTION_MODE_OVERLAY = android.view.Window.FEATURE_ACTION_MODE_OVERLAY;
|
||||
public static final long FEATURE_NO_TITLE = android.view.Window.FEATURE_NO_TITLE;
|
||||
public static final long FEATURE_PROGRESS = android.view.Window.FEATURE_PROGRESS;
|
||||
public static final long FEATURE_INDETERMINATE_PROGRESS = android.view.Window.FEATURE_INDETERMINATE_PROGRESS;
|
||||
|
||||
/**
|
||||
* Create a new instance for a context.
|
||||
*
|
||||
* @param context Context.
|
||||
*/
|
||||
private Window(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
|
||||
public interface Callback {
|
||||
/**
|
||||
* Called when a panel's menu item has been selected by the user.
|
||||
*
|
||||
* @param featureId The panel that the menu is in.
|
||||
* @param item The menu item that was selected.
|
||||
*
|
||||
* @return boolean Return true to finish processing of selection, or
|
||||
* false to perform the normal menu handling (calling its
|
||||
* Runnable or sending a Message to its target Handler).
|
||||
*/
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item);
|
||||
}
|
||||
}
|
@ -1,827 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 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.actionbarsherlock.widget;
|
||||
|
||||
import android.os.Build;
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.widget.IcsLinearLayout;
|
||||
import com.actionbarsherlock.internal.widget.IcsListPopupWindow;
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import com.actionbarsherlock.widget.ActivityChooserModel.ActivityChooserModelClient;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.database.DataSetObserver;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.PopupWindow;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* This class is a view for choosing an activity for handling a given {@link Intent}.
|
||||
* <p>
|
||||
* The view is composed of two adjacent buttons:
|
||||
* <ul>
|
||||
* <li>
|
||||
* The left button is an immediate action and allows one click activity choosing.
|
||||
* Tapping this button immediately executes the intent without requiring any further
|
||||
* user input. Long press on this button shows a popup for changing the default
|
||||
* activity.
|
||||
* </li>
|
||||
* <li>
|
||||
* The right button is an overflow action and provides an optimized menu
|
||||
* of additional activities. Tapping this button shows a popup anchored to this
|
||||
* view, listing the most frequently used activities. This list is initially
|
||||
* limited to a small number of items in frequency used order. The last item,
|
||||
* "Show all..." serves as an affordance to display all available activities.
|
||||
* </li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
class ActivityChooserView extends ViewGroup implements ActivityChooserModelClient {
|
||||
|
||||
/**
|
||||
* An adapter for displaying the activities in an {@link AdapterView}.
|
||||
*/
|
||||
private final ActivityChooserViewAdapter mAdapter;
|
||||
|
||||
/**
|
||||
* Implementation of various interfaces to avoid publishing them in the APIs.
|
||||
*/
|
||||
private final Callbacks mCallbacks;
|
||||
|
||||
/**
|
||||
* The content of this view.
|
||||
*/
|
||||
private final IcsLinearLayout mActivityChooserContent;
|
||||
|
||||
/**
|
||||
* Stores the background drawable to allow hiding and latter showing.
|
||||
*/
|
||||
private final Drawable mActivityChooserContentBackground;
|
||||
|
||||
/**
|
||||
* The expand activities action button;
|
||||
*/
|
||||
private final FrameLayout mExpandActivityOverflowButton;
|
||||
|
||||
/**
|
||||
* The image for the expand activities action button;
|
||||
*/
|
||||
private final ImageView mExpandActivityOverflowButtonImage;
|
||||
|
||||
/**
|
||||
* The default activities action button;
|
||||
*/
|
||||
private final FrameLayout mDefaultActivityButton;
|
||||
|
||||
/**
|
||||
* The image for the default activities action button;
|
||||
*/
|
||||
private final ImageView mDefaultActivityButtonImage;
|
||||
|
||||
/**
|
||||
* The maximal width of the list popup.
|
||||
*/
|
||||
private final int mListPopupMaxWidth;
|
||||
|
||||
/**
|
||||
* The ActionProvider hosting this view, if applicable.
|
||||
*/
|
||||
ActionProvider mProvider;
|
||||
|
||||
/**
|
||||
* Observer for the model data.
|
||||
*/
|
||||
private final DataSetObserver mModelDataSetOberver = new DataSetObserver() {
|
||||
|
||||
@Override
|
||||
public void onChanged() {
|
||||
super.onChanged();
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
@Override
|
||||
public void onInvalidated() {
|
||||
super.onInvalidated();
|
||||
mAdapter.notifyDataSetInvalidated();
|
||||
}
|
||||
};
|
||||
|
||||
private final OnGlobalLayoutListener mOnGlobalLayoutListener = new OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
if (isShowingPopup()) {
|
||||
if (!isShown()) {
|
||||
getListPopupWindow().dismiss();
|
||||
} else {
|
||||
getListPopupWindow().show();
|
||||
if (mProvider != null) {
|
||||
mProvider.subUiVisibilityChanged(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Popup window for showing the activity overflow list.
|
||||
*/
|
||||
private IcsListPopupWindow mListPopupWindow;
|
||||
|
||||
/**
|
||||
* Listener for the dismissal of the popup/alert.
|
||||
*/
|
||||
private PopupWindow.OnDismissListener mOnDismissListener;
|
||||
|
||||
/**
|
||||
* Flag whether a default activity currently being selected.
|
||||
*/
|
||||
private boolean mIsSelectingDefaultActivity;
|
||||
|
||||
/**
|
||||
* The count of activities in the popup.
|
||||
*/
|
||||
private int mInitialActivityCount = ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_DEFAULT;
|
||||
|
||||
/**
|
||||
* Flag whether this view is attached to a window.
|
||||
*/
|
||||
private boolean mIsAttachedToWindow;
|
||||
|
||||
/**
|
||||
* String resource for formatting content description of the default target.
|
||||
*/
|
||||
private int mDefaultActionButtonContentDescription;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param context The application environment.
|
||||
*/
|
||||
public ActivityChooserView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param context The application environment.
|
||||
* @param attrs A collection of attributes.
|
||||
*/
|
||||
public ActivityChooserView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param context The application environment.
|
||||
* @param attrs A collection of attributes.
|
||||
* @param defStyle The default style to apply to this view.
|
||||
*/
|
||||
public ActivityChooserView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mContext = context;
|
||||
|
||||
TypedArray attributesArray = context.obtainStyledAttributes(attrs,
|
||||
R.styleable.SherlockActivityChooserView, defStyle, 0);
|
||||
|
||||
mInitialActivityCount = attributesArray.getInt(
|
||||
R.styleable.SherlockActivityChooserView_initialActivityCount,
|
||||
ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_DEFAULT);
|
||||
|
||||
Drawable expandActivityOverflowButtonDrawable = attributesArray.getDrawable(
|
||||
R.styleable.SherlockActivityChooserView_expandActivityOverflowButtonDrawable);
|
||||
|
||||
attributesArray.recycle();
|
||||
|
||||
LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||
inflater.inflate(R.layout.abs__activity_chooser_view, this, true);
|
||||
|
||||
mCallbacks = new Callbacks();
|
||||
|
||||
mActivityChooserContent = (IcsLinearLayout) findViewById(R.id.abs__activity_chooser_view_content);
|
||||
mActivityChooserContentBackground = mActivityChooserContent.getBackground();
|
||||
|
||||
mDefaultActivityButton = (FrameLayout) findViewById(R.id.abs__default_activity_button);
|
||||
mDefaultActivityButton.setOnClickListener(mCallbacks);
|
||||
mDefaultActivityButton.setOnLongClickListener(mCallbacks);
|
||||
mDefaultActivityButtonImage = (ImageView) mDefaultActivityButton.findViewById(R.id.abs__image);
|
||||
|
||||
mExpandActivityOverflowButton = (FrameLayout) findViewById(R.id.abs__expand_activities_button);
|
||||
mExpandActivityOverflowButton.setOnClickListener(mCallbacks);
|
||||
mExpandActivityOverflowButtonImage =
|
||||
(ImageView) mExpandActivityOverflowButton.findViewById(R.id.abs__image);
|
||||
mExpandActivityOverflowButtonImage.setImageDrawable(expandActivityOverflowButtonDrawable);
|
||||
|
||||
mAdapter = new ActivityChooserViewAdapter();
|
||||
mAdapter.registerDataSetObserver(new DataSetObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
super.onChanged();
|
||||
updateAppearance();
|
||||
}
|
||||
});
|
||||
|
||||
Resources resources = context.getResources();
|
||||
mListPopupMaxWidth = Math.max(resources.getDisplayMetrics().widthPixels / 2,
|
||||
resources.getDimensionPixelSize(R.dimen.abs__config_prefDialogWidth));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void setActivityChooserModel(ActivityChooserModel dataModel) {
|
||||
mAdapter.setDataModel(dataModel);
|
||||
if (isShowingPopup()) {
|
||||
dismissPopup();
|
||||
showPopup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the background for the button that expands the activity
|
||||
* overflow list.
|
||||
*
|
||||
* <strong>Note:</strong> Clients would like to set this drawable
|
||||
* as a clue about the action the chosen activity will perform. For
|
||||
* example, if a share activity is to be chosen the drawable should
|
||||
* give a clue that sharing is to be performed.
|
||||
*
|
||||
* @param drawable The drawable.
|
||||
*/
|
||||
public void setExpandActivityOverflowButtonDrawable(Drawable drawable) {
|
||||
mExpandActivityOverflowButtonImage.setImageDrawable(drawable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content description for the button that expands the activity
|
||||
* overflow list.
|
||||
*
|
||||
* description as a clue about the action performed by the button.
|
||||
* For example, if a share activity is to be chosen the content
|
||||
* description should be something like "Share with".
|
||||
*
|
||||
* @param resourceId The content description resource id.
|
||||
*/
|
||||
public void setExpandActivityOverflowButtonContentDescription(int resourceId) {
|
||||
CharSequence contentDescription = mContext.getString(resourceId);
|
||||
mExpandActivityOverflowButtonImage.setContentDescription(contentDescription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the provider hosting this view, if applicable.
|
||||
* @hide Internal use only
|
||||
*/
|
||||
public void setProvider(ActionProvider provider) {
|
||||
mProvider = provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the popup window with activities.
|
||||
*
|
||||
* @return True if the popup was shown, false if already showing.
|
||||
*/
|
||||
public boolean showPopup() {
|
||||
if (isShowingPopup() || !mIsAttachedToWindow) {
|
||||
return false;
|
||||
}
|
||||
mIsSelectingDefaultActivity = false;
|
||||
showPopupUnchecked(mInitialActivityCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the popup no matter if it was already showing.
|
||||
*
|
||||
* @param maxActivityCount The max number of activities to display.
|
||||
*/
|
||||
private void showPopupUnchecked(int maxActivityCount) {
|
||||
if (mAdapter.getDataModel() == null) {
|
||||
throw new IllegalStateException("No data model. Did you call #setDataModel?");
|
||||
}
|
||||
|
||||
getViewTreeObserver().addOnGlobalLayoutListener(mOnGlobalLayoutListener);
|
||||
|
||||
final boolean defaultActivityButtonShown =
|
||||
mDefaultActivityButton.getVisibility() == VISIBLE;
|
||||
|
||||
final int activityCount = mAdapter.getActivityCount();
|
||||
final int maxActivityCountOffset = defaultActivityButtonShown ? 1 : 0;
|
||||
if (maxActivityCount != ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED
|
||||
&& activityCount > maxActivityCount + maxActivityCountOffset) {
|
||||
mAdapter.setShowFooterView(true);
|
||||
mAdapter.setMaxActivityCount(maxActivityCount - 1);
|
||||
} else {
|
||||
mAdapter.setShowFooterView(false);
|
||||
mAdapter.setMaxActivityCount(maxActivityCount);
|
||||
}
|
||||
|
||||
IcsListPopupWindow popupWindow = getListPopupWindow();
|
||||
if (!popupWindow.isShowing()) {
|
||||
if (mIsSelectingDefaultActivity || !defaultActivityButtonShown) {
|
||||
mAdapter.setShowDefaultActivity(true, defaultActivityButtonShown);
|
||||
} else {
|
||||
mAdapter.setShowDefaultActivity(false, false);
|
||||
}
|
||||
final int contentWidth = Math.min(mAdapter.measureContentWidth(), mListPopupMaxWidth);
|
||||
popupWindow.setContentWidth(contentWidth);
|
||||
popupWindow.show();
|
||||
if (mProvider != null) {
|
||||
mProvider.subUiVisibilityChanged(true);
|
||||
}
|
||||
popupWindow.getListView().setContentDescription(mContext.getString(
|
||||
R.string.abs__activitychooserview_choose_application));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismisses the popup window with activities.
|
||||
*
|
||||
* @return True if dismissed, false if already dismissed.
|
||||
*/
|
||||
public boolean dismissPopup() {
|
||||
if (isShowingPopup()) {
|
||||
getListPopupWindow().dismiss();
|
||||
ViewTreeObserver viewTreeObserver = getViewTreeObserver();
|
||||
if (viewTreeObserver.isAlive()) {
|
||||
viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the popup window with activities is shown.
|
||||
*
|
||||
* @return True if the popup is shown.
|
||||
*/
|
||||
public boolean isShowingPopup() {
|
||||
return getListPopupWindow().isShowing();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
ActivityChooserModel dataModel = mAdapter.getDataModel();
|
||||
if (dataModel != null) {
|
||||
dataModel.registerObserver(mModelDataSetOberver);
|
||||
}
|
||||
mIsAttachedToWindow = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
ActivityChooserModel dataModel = mAdapter.getDataModel();
|
||||
if (dataModel != null) {
|
||||
try {
|
||||
dataModel.unregisterObserver(mModelDataSetOberver);
|
||||
} catch (IllegalStateException e) {
|
||||
//Oh, well... fixes issue #557
|
||||
}
|
||||
}
|
||||
ViewTreeObserver viewTreeObserver = getViewTreeObserver();
|
||||
if (viewTreeObserver.isAlive()) {
|
||||
viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
|
||||
}
|
||||
mIsAttachedToWindow = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
View child = mActivityChooserContent;
|
||||
// If the default action is not visible we want to be as tall as the
|
||||
// ActionBar so if this widget is used in the latter it will look as
|
||||
// a normal action button.
|
||||
if (mDefaultActivityButton.getVisibility() != VISIBLE) {
|
||||
heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
|
||||
MeasureSpec.EXACTLY);
|
||||
}
|
||||
measureChild(child, widthMeasureSpec, heightMeasureSpec);
|
||||
setMeasuredDimension(child.getMeasuredWidth(), child.getMeasuredHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
mActivityChooserContent.layout(0, 0, right - left, bottom - top);
|
||||
if (getListPopupWindow().isShowing()) {
|
||||
showPopupUnchecked(mAdapter.getMaxActivityCount());
|
||||
} else {
|
||||
dismissPopup();
|
||||
}
|
||||
}
|
||||
|
||||
public ActivityChooserModel getDataModel() {
|
||||
return mAdapter.getDataModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a listener to receive a callback when the popup is dismissed.
|
||||
*
|
||||
* @param listener The listener to be notified.
|
||||
*/
|
||||
public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
|
||||
mOnDismissListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial count of items shown in the activities popup
|
||||
* i.e. the items before the popup is expanded. This is an upper
|
||||
* bound since it is not guaranteed that such number of intent
|
||||
* handlers exist.
|
||||
*
|
||||
* @param itemCount The initial popup item count.
|
||||
*/
|
||||
public void setInitialActivityCount(int itemCount) {
|
||||
mInitialActivityCount = itemCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a content description of the default action button. This
|
||||
* resource should be a string taking one formatting argument and
|
||||
* will be used for formatting the content description of the button
|
||||
* dynamically as the default target changes. For example, a resource
|
||||
* pointing to the string "share with %1$s" will result in a content
|
||||
* description "share with Bluetooth" for the Bluetooth activity.
|
||||
*
|
||||
* @param resourceId The resource id.
|
||||
*/
|
||||
public void setDefaultActionButtonContentDescription(int resourceId) {
|
||||
mDefaultActionButtonContentDescription = resourceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list popup window which is lazily initialized.
|
||||
*
|
||||
* @return The popup.
|
||||
*/
|
||||
private IcsListPopupWindow getListPopupWindow() {
|
||||
if (mListPopupWindow == null) {
|
||||
mListPopupWindow = new IcsListPopupWindow(getContext());
|
||||
mListPopupWindow.setAdapter(mAdapter);
|
||||
mListPopupWindow.setAnchorView(ActivityChooserView.this);
|
||||
mListPopupWindow.setModal(true);
|
||||
mListPopupWindow.setOnItemClickListener(mCallbacks);
|
||||
mListPopupWindow.setOnDismissListener(mCallbacks);
|
||||
}
|
||||
return mListPopupWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the buttons state.
|
||||
*/
|
||||
private void updateAppearance() {
|
||||
// Expand overflow button.
|
||||
if (mAdapter.getCount() > 0) {
|
||||
mExpandActivityOverflowButton.setEnabled(true);
|
||||
} else {
|
||||
mExpandActivityOverflowButton.setEnabled(false);
|
||||
}
|
||||
// Default activity button.
|
||||
final int activityCount = mAdapter.getActivityCount();
|
||||
final int historySize = mAdapter.getHistorySize();
|
||||
if (activityCount > 0 && historySize > 0) {
|
||||
mDefaultActivityButton.setVisibility(VISIBLE);
|
||||
ResolveInfo activity = mAdapter.getDefaultActivity();
|
||||
PackageManager packageManager = mContext.getPackageManager();
|
||||
mDefaultActivityButtonImage.setImageDrawable(activity.loadIcon(packageManager));
|
||||
if (mDefaultActionButtonContentDescription != 0) {
|
||||
CharSequence label = activity.loadLabel(packageManager);
|
||||
String contentDescription = mContext.getString(
|
||||
mDefaultActionButtonContentDescription, label);
|
||||
mDefaultActivityButton.setContentDescription(contentDescription);
|
||||
}
|
||||
} else {
|
||||
mDefaultActivityButton.setVisibility(View.GONE);
|
||||
}
|
||||
// Activity chooser content.
|
||||
if (mDefaultActivityButton.getVisibility() == VISIBLE) {
|
||||
mActivityChooserContent.setBackgroundDrawable(mActivityChooserContentBackground);
|
||||
} else {
|
||||
mActivityChooserContent.setBackgroundDrawable(null);
|
||||
mActivityChooserContent.setPadding(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface implementation to avoid publishing them in the APIs.
|
||||
*/
|
||||
private class Callbacks implements AdapterView.OnItemClickListener,
|
||||
View.OnClickListener, View.OnLongClickListener, PopupWindow.OnDismissListener {
|
||||
|
||||
// AdapterView#OnItemClickListener
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
ActivityChooserViewAdapter adapter = (ActivityChooserViewAdapter) parent.getAdapter();
|
||||
final int itemViewType = adapter.getItemViewType(position);
|
||||
switch (itemViewType) {
|
||||
case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_FOOTER: {
|
||||
showPopupUnchecked(ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED);
|
||||
} break;
|
||||
case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_ACTIVITY: {
|
||||
dismissPopup();
|
||||
if (mIsSelectingDefaultActivity) {
|
||||
// The item at position zero is the default already.
|
||||
if (position > 0) {
|
||||
mAdapter.getDataModel().setDefaultActivity(position);
|
||||
}
|
||||
} else {
|
||||
// If the default target is not shown in the list, the first
|
||||
// item in the model is default action => adjust index
|
||||
position = mAdapter.getShowDefaultActivity() ? position : position + 1;
|
||||
Intent launchIntent = mAdapter.getDataModel().chooseActivity(position);
|
||||
if (launchIntent != null) {
|
||||
mContext.startActivity(launchIntent);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
// View.OnClickListener
|
||||
public void onClick(View view) {
|
||||
if (view == mDefaultActivityButton) {
|
||||
dismissPopup();
|
||||
ResolveInfo defaultActivity = mAdapter.getDefaultActivity();
|
||||
final int index = mAdapter.getDataModel().getActivityIndex(defaultActivity);
|
||||
Intent launchIntent = mAdapter.getDataModel().chooseActivity(index);
|
||||
if (launchIntent != null) {
|
||||
mContext.startActivity(launchIntent);
|
||||
}
|
||||
} else if (view == mExpandActivityOverflowButton) {
|
||||
mIsSelectingDefaultActivity = false;
|
||||
showPopupUnchecked(mInitialActivityCount);
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
// OnLongClickListener#onLongClick
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
if (view == mDefaultActivityButton) {
|
||||
if (mAdapter.getCount() > 0) {
|
||||
mIsSelectingDefaultActivity = true;
|
||||
showPopupUnchecked(mInitialActivityCount);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// PopUpWindow.OnDismissListener#onDismiss
|
||||
public void onDismiss() {
|
||||
notifyOnDismissListener();
|
||||
if (mProvider != null) {
|
||||
mProvider.subUiVisibilityChanged(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyOnDismissListener() {
|
||||
if (mOnDismissListener != null) {
|
||||
mOnDismissListener.onDismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SetActivated {
|
||||
public static void invoke(View view, boolean activated) {
|
||||
view.setActivated(activated);
|
||||
}
|
||||
}
|
||||
|
||||
private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
|
||||
|
||||
/**
|
||||
* Adapter for backing the list of activities shown in the popup.
|
||||
*/
|
||||
private class ActivityChooserViewAdapter extends BaseAdapter {
|
||||
|
||||
public static final int MAX_ACTIVITY_COUNT_UNLIMITED = Integer.MAX_VALUE;
|
||||
|
||||
public static final int MAX_ACTIVITY_COUNT_DEFAULT = 4;
|
||||
|
||||
private static final int ITEM_VIEW_TYPE_ACTIVITY = 0;
|
||||
|
||||
private static final int ITEM_VIEW_TYPE_FOOTER = 1;
|
||||
|
||||
private static final int ITEM_VIEW_TYPE_COUNT = 3;
|
||||
|
||||
private ActivityChooserModel mDataModel;
|
||||
|
||||
private int mMaxActivityCount = MAX_ACTIVITY_COUNT_DEFAULT;
|
||||
|
||||
private boolean mShowDefaultActivity;
|
||||
|
||||
private boolean mHighlightDefaultActivity;
|
||||
|
||||
private boolean mShowFooterView;
|
||||
|
||||
public void setDataModel(ActivityChooserModel dataModel) {
|
||||
ActivityChooserModel oldDataModel = mAdapter.getDataModel();
|
||||
if (oldDataModel != null && isShown()) {
|
||||
try {
|
||||
oldDataModel.unregisterObserver(mModelDataSetOberver);
|
||||
} catch (IllegalStateException e) {
|
||||
//Oh, well... fixes issue #557
|
||||
}
|
||||
}
|
||||
mDataModel = dataModel;
|
||||
if (dataModel != null && isShown()) {
|
||||
dataModel.registerObserver(mModelDataSetOberver);
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (mShowFooterView && position == getCount() - 1) {
|
||||
return ITEM_VIEW_TYPE_FOOTER;
|
||||
} else {
|
||||
return ITEM_VIEW_TYPE_ACTIVITY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewTypeCount() {
|
||||
return ITEM_VIEW_TYPE_COUNT;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
int count = 0;
|
||||
int activityCount = mDataModel.getActivityCount();
|
||||
if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) {
|
||||
activityCount--;
|
||||
}
|
||||
count = Math.min(activityCount, mMaxActivityCount);
|
||||
if (mShowFooterView) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public Object getItem(int position) {
|
||||
final int itemViewType = getItemViewType(position);
|
||||
switch (itemViewType) {
|
||||
case ITEM_VIEW_TYPE_FOOTER:
|
||||
return null;
|
||||
case ITEM_VIEW_TYPE_ACTIVITY:
|
||||
if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) {
|
||||
position++;
|
||||
}
|
||||
return mDataModel.getActivity(position);
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
final int itemViewType = getItemViewType(position);
|
||||
switch (itemViewType) {
|
||||
case ITEM_VIEW_TYPE_FOOTER:
|
||||
if (convertView == null || convertView.getId() != ITEM_VIEW_TYPE_FOOTER) {
|
||||
convertView = LayoutInflater.from(getContext()).inflate(
|
||||
R.layout.abs__activity_chooser_view_list_item, parent, false);
|
||||
convertView.setId(ITEM_VIEW_TYPE_FOOTER);
|
||||
TextView titleView = (TextView) convertView.findViewById(R.id.abs__title);
|
||||
titleView.setText(mContext.getString(
|
||||
R.string.abs__activity_chooser_view_see_all));
|
||||
}
|
||||
return convertView;
|
||||
case ITEM_VIEW_TYPE_ACTIVITY:
|
||||
if (convertView == null || convertView.getId() != R.id.abs__list_item) {
|
||||
convertView = LayoutInflater.from(getContext()).inflate(
|
||||
R.layout.abs__activity_chooser_view_list_item, parent, false);
|
||||
}
|
||||
PackageManager packageManager = mContext.getPackageManager();
|
||||
// Set the icon
|
||||
ImageView iconView = (ImageView) convertView.findViewById(R.id.abs__icon);
|
||||
ResolveInfo activity = (ResolveInfo) getItem(position);
|
||||
iconView.setImageDrawable(activity.loadIcon(packageManager));
|
||||
// Set the title.
|
||||
TextView titleView = (TextView) convertView.findViewById(R.id.abs__title);
|
||||
titleView.setText(activity.loadLabel(packageManager));
|
||||
if (IS_HONEYCOMB) {
|
||||
// Highlight the default.
|
||||
if (mShowDefaultActivity && position == 0 && mHighlightDefaultActivity) {
|
||||
SetActivated.invoke(convertView, true);
|
||||
} else {
|
||||
SetActivated.invoke(convertView, false);
|
||||
}
|
||||
}
|
||||
return convertView;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
public int measureContentWidth() {
|
||||
// The user may have specified some of the target not to be shown but we
|
||||
// want to measure all of them since after expansion they should fit.
|
||||
final int oldMaxActivityCount = mMaxActivityCount;
|
||||
mMaxActivityCount = MAX_ACTIVITY_COUNT_UNLIMITED;
|
||||
|
||||
int contentWidth = 0;
|
||||
View itemView = null;
|
||||
|
||||
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
final int count = getCount();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
itemView = getView(i, itemView, null);
|
||||
itemView.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
contentWidth = Math.max(contentWidth, itemView.getMeasuredWidth());
|
||||
}
|
||||
|
||||
mMaxActivityCount = oldMaxActivityCount;
|
||||
|
||||
return contentWidth;
|
||||
}
|
||||
|
||||
public void setMaxActivityCount(int maxActivityCount) {
|
||||
if (mMaxActivityCount != maxActivityCount) {
|
||||
mMaxActivityCount = maxActivityCount;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public ResolveInfo getDefaultActivity() {
|
||||
return mDataModel.getDefaultActivity();
|
||||
}
|
||||
|
||||
public void setShowFooterView(boolean showFooterView) {
|
||||
if (mShowFooterView != showFooterView) {
|
||||
mShowFooterView = showFooterView;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public int getActivityCount() {
|
||||
return mDataModel.getActivityCount();
|
||||
}
|
||||
|
||||
public int getHistorySize() {
|
||||
return mDataModel.getHistorySize();
|
||||
}
|
||||
|
||||
public int getMaxActivityCount() {
|
||||
return mMaxActivityCount;
|
||||
}
|
||||
|
||||
public ActivityChooserModel getDataModel() {
|
||||
return mDataModel;
|
||||
}
|
||||
|
||||
public void setShowDefaultActivity(boolean showDefaultActivity,
|
||||
boolean highlightDefaultActivity) {
|
||||
if (mShowDefaultActivity != showDefaultActivity
|
||||
|| mHighlightDefaultActivity != highlightDefaultActivity) {
|
||||
mShowDefaultActivity = showDefaultActivity;
|
||||
mHighlightDefaultActivity = highlightDefaultActivity;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getShowDefaultActivity() {
|
||||
return mShowDefaultActivity;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,316 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 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.actionbarsherlock.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.MenuItem.OnMenuItemClickListener;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
import com.actionbarsherlock.widget.ActivityChooserModel.OnChooseActivityListener;
|
||||
|
||||
/**
|
||||
* This is a provider for a share action. It is responsible for creating views
|
||||
* that enable data sharing and also to show a sub menu with sharing activities
|
||||
* if the hosting item is placed on the overflow menu.
|
||||
* <p>
|
||||
* Here is how to use the action provider with custom backing file in a {@link MenuItem}:
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>
|
||||
* <code>
|
||||
* // In Activity#onCreateOptionsMenu
|
||||
* public boolean onCreateOptionsMenu(Menu menu) {
|
||||
* // Get the menu item.
|
||||
* MenuItem menuItem = menu.findItem(R.id.my_menu_item);
|
||||
* // Get the provider and hold onto it to set/change the share intent.
|
||||
* mShareActionProvider = (ShareActionProvider) menuItem.getActionProvider();
|
||||
* // Set history different from the default before getting the action
|
||||
* // view since a call to {@link MenuItem#getActionView() MenuItem.getActionView()} calls
|
||||
* // {@link ActionProvider#onCreateActionView()} which uses the backing file name. Omit this
|
||||
* // line if using the default share history file is desired.
|
||||
* mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");
|
||||
* . . .
|
||||
* }
|
||||
*
|
||||
* // Somewhere in the application.
|
||||
* public void doShare(Intent shareIntent) {
|
||||
* // When you want to share set the share intent.
|
||||
* mShareActionProvider.setShareIntent(shareIntent);
|
||||
* }
|
||||
* </pre>
|
||||
* </code>
|
||||
* </p>
|
||||
* <p>
|
||||
* <strong>Note:</strong> While the sample snippet demonstrates how to use this provider
|
||||
* in the context of a menu item, the use of the provider is not limited to menu items.
|
||||
* </p>
|
||||
*
|
||||
* @see ActionProvider
|
||||
*/
|
||||
public class ShareActionProvider extends ActionProvider {
|
||||
|
||||
/**
|
||||
* Listener for the event of selecting a share target.
|
||||
*/
|
||||
public interface OnShareTargetSelectedListener {
|
||||
|
||||
/**
|
||||
* Called when a share target has been selected. The client can
|
||||
* decide whether to handle the intent or rely on the default
|
||||
* behavior which is launching it.
|
||||
* <p>
|
||||
* <strong>Note:</strong> Modifying the intent is not permitted and
|
||||
* any changes to the latter will be ignored.
|
||||
* </p>
|
||||
*
|
||||
* @param source The source of the notification.
|
||||
* @param intent The intent for launching the chosen share target.
|
||||
* @return Whether the client has handled the intent.
|
||||
*/
|
||||
public boolean onShareTargetSelected(ShareActionProvider source, Intent intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* The default for the maximal number of activities shown in the sub-menu.
|
||||
*/
|
||||
private static final int DEFAULT_INITIAL_ACTIVITY_COUNT = 4;
|
||||
|
||||
/**
|
||||
* The the maximum number activities shown in the sub-menu.
|
||||
*/
|
||||
private int mMaxShownActivityCount = DEFAULT_INITIAL_ACTIVITY_COUNT;
|
||||
|
||||
/**
|
||||
* Listener for handling menu item clicks.
|
||||
*/
|
||||
private final ShareMenuItemOnMenuItemClickListener mOnMenuItemClickListener =
|
||||
new ShareMenuItemOnMenuItemClickListener();
|
||||
|
||||
/**
|
||||
* The default name for storing share history.
|
||||
*/
|
||||
public static final String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml";
|
||||
|
||||
/**
|
||||
* Context for accessing resources.
|
||||
*/
|
||||
private final Context mContext;
|
||||
|
||||
/**
|
||||
* The name of the file with share history data.
|
||||
*/
|
||||
private String mShareHistoryFileName = DEFAULT_SHARE_HISTORY_FILE_NAME;
|
||||
|
||||
private OnShareTargetSelectedListener mOnShareTargetSelectedListener;
|
||||
|
||||
private OnChooseActivityListener mOnChooseActivityListener;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param context Context for accessing resources.
|
||||
*/
|
||||
public ShareActionProvider(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a listener to be notified when a share target has been selected.
|
||||
* The listener can optionally decide to handle the selection and
|
||||
* not rely on the default behavior which is to launch the activity.
|
||||
* <p>
|
||||
* <strong>Note:</strong> If you choose the backing share history file
|
||||
* you will still be notified in this callback.
|
||||
* </p>
|
||||
* @param listener The listener.
|
||||
*/
|
||||
public void setOnShareTargetSelectedListener(OnShareTargetSelectedListener listener) {
|
||||
mOnShareTargetSelectedListener = listener;
|
||||
setActivityChooserPolicyIfNeeded();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public View onCreateActionView() {
|
||||
// Create the view and set its data model.
|
||||
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
|
||||
ActivityChooserView activityChooserView = new ActivityChooserView(mContext);
|
||||
activityChooserView.setActivityChooserModel(dataModel);
|
||||
|
||||
// Lookup and set the expand action icon.
|
||||
TypedValue outTypedValue = new TypedValue();
|
||||
mContext.getTheme().resolveAttribute(R.attr.actionModeShareDrawable, outTypedValue, true);
|
||||
Drawable drawable = mContext.getResources().getDrawable(outTypedValue.resourceId);
|
||||
activityChooserView.setExpandActivityOverflowButtonDrawable(drawable);
|
||||
activityChooserView.setProvider(this);
|
||||
|
||||
// Set content description.
|
||||
activityChooserView.setDefaultActionButtonContentDescription(
|
||||
R.string.abs__shareactionprovider_share_with_application);
|
||||
activityChooserView.setExpandActivityOverflowButtonContentDescription(
|
||||
R.string.abs__shareactionprovider_share_with);
|
||||
|
||||
return activityChooserView;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean hasSubMenu() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onPrepareSubMenu(SubMenu subMenu) {
|
||||
// Clear since the order of items may change.
|
||||
subMenu.clear();
|
||||
|
||||
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
|
||||
PackageManager packageManager = mContext.getPackageManager();
|
||||
|
||||
final int expandedActivityCount = dataModel.getActivityCount();
|
||||
final int collapsedActivityCount = Math.min(expandedActivityCount, mMaxShownActivityCount);
|
||||
|
||||
// Populate the sub-menu with a sub set of the activities.
|
||||
for (int i = 0; i < collapsedActivityCount; i++) {
|
||||
ResolveInfo activity = dataModel.getActivity(i);
|
||||
subMenu.add(0, i, i, activity.loadLabel(packageManager))
|
||||
.setIcon(activity.loadIcon(packageManager))
|
||||
.setOnMenuItemClickListener(mOnMenuItemClickListener);
|
||||
}
|
||||
|
||||
if (collapsedActivityCount < expandedActivityCount) {
|
||||
// Add a sub-menu for showing all activities as a list item.
|
||||
SubMenu expandedSubMenu = subMenu.addSubMenu(Menu.NONE, collapsedActivityCount,
|
||||
collapsedActivityCount,
|
||||
mContext.getString(R.string.abs__activity_chooser_view_see_all));
|
||||
for (int i = 0; i < expandedActivityCount; i++) {
|
||||
ResolveInfo activity = dataModel.getActivity(i);
|
||||
expandedSubMenu.add(0, i, i, activity.loadLabel(packageManager))
|
||||
.setIcon(activity.loadIcon(packageManager))
|
||||
.setOnMenuItemClickListener(mOnMenuItemClickListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the file name of a file for persisting the share history which
|
||||
* history will be used for ordering share targets. This file will be used
|
||||
* for all view created by {@link #onCreateActionView()}. Defaults to
|
||||
* {@link #DEFAULT_SHARE_HISTORY_FILE_NAME}. Set to <code>null</code>
|
||||
* if share history should not be persisted between sessions.
|
||||
* <p>
|
||||
* <strong>Note:</strong> The history file name can be set any time, however
|
||||
* only the action views created by {@link #onCreateActionView()} after setting
|
||||
* the file name will be backed by the provided file.
|
||||
* <p>
|
||||
*
|
||||
* @param shareHistoryFile The share history file name.
|
||||
*/
|
||||
public void setShareHistoryFileName(String shareHistoryFile) {
|
||||
mShareHistoryFileName = shareHistoryFile;
|
||||
setActivityChooserPolicyIfNeeded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an intent with information about the share action. Here is a
|
||||
* sample for constructing a share intent:
|
||||
* <p>
|
||||
* <pre>
|
||||
* <code>
|
||||
* Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
||||
* shareIntent.setType("image/*");
|
||||
* Uri uri = Uri.fromFile(new File(getFilesDir(), "foo.jpg"));
|
||||
* shareIntent.putExtra(Intent.EXTRA_STREAM, uri.toString());
|
||||
* </pre>
|
||||
* </code>
|
||||
* </p>
|
||||
*
|
||||
* @param shareIntent The share intent.
|
||||
*
|
||||
* @see Intent#ACTION_SEND
|
||||
* @see Intent#ACTION_SEND_MULTIPLE
|
||||
*/
|
||||
public void setShareIntent(Intent shareIntent) {
|
||||
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext,
|
||||
mShareHistoryFileName);
|
||||
dataModel.setIntent(shareIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reusable listener for handling share item clicks.
|
||||
*/
|
||||
private class ShareMenuItemOnMenuItemClickListener implements OnMenuItemClickListener {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext,
|
||||
mShareHistoryFileName);
|
||||
final int itemId = item.getItemId();
|
||||
Intent launchIntent = dataModel.chooseActivity(itemId);
|
||||
if (launchIntent != null) {
|
||||
mContext.startActivity(launchIntent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the activity chooser policy of the model backed by the current
|
||||
* share history file if needed which is if there is a registered callback.
|
||||
*/
|
||||
private void setActivityChooserPolicyIfNeeded() {
|
||||
if (mOnShareTargetSelectedListener == null) {
|
||||
return;
|
||||
}
|
||||
if (mOnChooseActivityListener == null) {
|
||||
mOnChooseActivityListener = new ShareAcitivityChooserModelPolicy();
|
||||
}
|
||||
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
|
||||
dataModel.setOnChooseActivityListener(mOnChooseActivityListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Policy that delegates to the {@link OnShareTargetSelectedListener}, if such.
|
||||
*/
|
||||
private class ShareAcitivityChooserModelPolicy implements OnChooseActivityListener {
|
||||
@Override
|
||||
public boolean onChooseActivity(ActivityChooserModel host, Intent intent) {
|
||||
if (mOnShareTargetSelectedListener != null) {
|
||||
return mOnShareTargetSelectedListener.onShareTargetSelected(
|
||||
ShareActionProvider.this, intent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,733 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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.actionbarsherlock.widget;
|
||||
|
||||
import android.app.SearchManager;
|
||||
import android.app.SearchableInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.widget.ResourceCursorAdapter;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.TextAppearanceSpan;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import com.actionbarsherlock.R;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* Provides the contents for the suggestion drop-down list.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
class SuggestionsAdapter extends ResourceCursorAdapter implements OnClickListener {
|
||||
|
||||
private static final boolean DBG = false;
|
||||
private static final String LOG_TAG = "SuggestionsAdapter";
|
||||
private static final int QUERY_LIMIT = 50;
|
||||
|
||||
static final int REFINE_NONE = 0;
|
||||
static final int REFINE_BY_ENTRY = 1;
|
||||
static final int REFINE_ALL = 2;
|
||||
|
||||
private SearchManager mSearchManager;
|
||||
private SearchView mSearchView;
|
||||
private Context mProviderContext;
|
||||
private WeakHashMap<String, Drawable.ConstantState> mOutsideDrawablesCache;
|
||||
private boolean mClosed = false;
|
||||
private int mQueryRefinement = REFINE_BY_ENTRY;
|
||||
|
||||
// URL color
|
||||
private ColorStateList mUrlColor;
|
||||
|
||||
static final int INVALID_INDEX = -1;
|
||||
|
||||
// Cached column indexes, updated when the cursor changes.
|
||||
private int mText1Col = INVALID_INDEX;
|
||||
private int mText2Col = INVALID_INDEX;
|
||||
private int mText2UrlCol = INVALID_INDEX;
|
||||
private int mIconName1Col = INVALID_INDEX;
|
||||
private int mIconName2Col = INVALID_INDEX;
|
||||
private int mFlagsCol = INVALID_INDEX;
|
||||
|
||||
// private final Runnable mStartSpinnerRunnable;
|
||||
// private final Runnable mStopSpinnerRunnable;
|
||||
|
||||
/**
|
||||
* The amount of time we delay in the filter when the user presses the delete key.
|
||||
*/
|
||||
//private static final long DELETE_KEY_POST_DELAY = 500L;
|
||||
|
||||
public SuggestionsAdapter(Context context, SearchView searchView,
|
||||
SearchableInfo mSearchable, WeakHashMap<String, Drawable.ConstantState> outsideDrawablesCache) {
|
||||
super(context,
|
||||
R.layout.abs__search_dropdown_item_icons_2line,
|
||||
null, // no initial cursor
|
||||
true); // auto-requery
|
||||
mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
|
||||
mProviderContext = mContext;
|
||||
mSearchView = searchView;
|
||||
|
||||
mOutsideDrawablesCache = outsideDrawablesCache;
|
||||
|
||||
// mStartSpinnerRunnable = new Runnable() {
|
||||
// public void run() {
|
||||
// // mSearchView.setWorking(true); // TODO:
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// mStopSpinnerRunnable = new Runnable() {
|
||||
// public void run() {
|
||||
// // mSearchView.setWorking(false); // TODO:
|
||||
// }
|
||||
// };
|
||||
|
||||
// delay 500ms when deleting
|
||||
// TODO getFilter().setDelayer(new Filter.Delayer() {
|
||||
//
|
||||
// private int mPreviousLength = 0;
|
||||
//
|
||||
// public long getPostingDelay(CharSequence constraint) {
|
||||
// if (constraint == null) return 0;
|
||||
//
|
||||
// long delay = constraint.length() < mPreviousLength ? DELETE_KEY_POST_DELAY : 0;
|
||||
// mPreviousLength = constraint.length();
|
||||
// return delay;
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables query refinement for all suggestions. This means that an additional icon
|
||||
* will be shown for each entry. When clicked, the suggested text on that line will be
|
||||
* copied to the query text field.
|
||||
* <p>
|
||||
*
|
||||
* @param refineWhat which queries to refine. Possible values are {@link #REFINE_NONE},
|
||||
* {@link #REFINE_BY_ENTRY}, and {@link #REFINE_ALL}.
|
||||
*/
|
||||
public void setQueryRefinement(int refineWhat) {
|
||||
mQueryRefinement = refineWhat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current query refinement preference.
|
||||
* @return value of query refinement preference
|
||||
*/
|
||||
public int getQueryRefinement() {
|
||||
return mQueryRefinement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to always return <code>false</code>, since we cannot be sure that
|
||||
* suggestion sources return stable IDs.
|
||||
*/
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the search suggestions provider to obtain a live cursor. This will be called
|
||||
* in a worker thread, so it's OK if the query is slow (e.g. round trip for suggestions).
|
||||
* The results will be processed in the UI thread and changeCursor() will be called.
|
||||
*/
|
||||
@Override
|
||||
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
|
||||
if (DBG) Log.d(LOG_TAG, "runQueryOnBackgroundThread(" + constraint + ")");
|
||||
String query = (constraint == null) ? "" : constraint.toString();
|
||||
/**
|
||||
* for in app search we show the progress spinner until the cursor is returned with
|
||||
* the results.
|
||||
*/
|
||||
Cursor cursor = null;
|
||||
if (mSearchView.getVisibility() != View.VISIBLE
|
||||
|| mSearchView.getWindowVisibility() != View.VISIBLE) {
|
||||
return null;
|
||||
}
|
||||
//mSearchView.getWindow().getDecorView().post(mStartSpinnerRunnable); // TODO:
|
||||
try {
|
||||
cursor = getSuggestions(query, QUERY_LIMIT);
|
||||
// trigger fill window so the spinner stays up until the results are copied over and
|
||||
// closer to being ready
|
||||
if (cursor != null) {
|
||||
cursor.getCount();
|
||||
return cursor;
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(LOG_TAG, "Search suggestions query threw an exception.", e);
|
||||
}
|
||||
// If cursor is null or an exception was thrown, stop the spinner and return null.
|
||||
// changeCursor doesn't get called if cursor is null
|
||||
// mSearchView.getWindow().getDecorView().post(mStopSpinnerRunnable); // TODO:
|
||||
return null;
|
||||
}
|
||||
|
||||
public Cursor getSuggestions(String query, int limit) {
|
||||
Uri.Builder uriBuilder = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.query("") // TODO: Remove, workaround for a bug in Uri.writeToParcel()
|
||||
.fragment(""); // TODO: Remove, workaround for a bug in Uri.writeToParcel()
|
||||
|
||||
// append standard suggestion query path
|
||||
uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY);
|
||||
|
||||
// inject query, either as selection args or inline
|
||||
uriBuilder.appendPath(query);
|
||||
|
||||
if (limit > 0) {
|
||||
uriBuilder.appendQueryParameter(SearchManager.SUGGEST_PARAMETER_LIMIT, String.valueOf(limit));
|
||||
}
|
||||
|
||||
Uri uri = uriBuilder.build();
|
||||
|
||||
// finally, make the query
|
||||
return mContext.getContentResolver().query(uri, null, null, null, null);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (DBG) Log.d(LOG_TAG, "close()");
|
||||
changeCursor(null);
|
||||
mClosed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDataSetChanged() {
|
||||
if (DBG) Log.d(LOG_TAG, "notifyDataSetChanged");
|
||||
super.notifyDataSetChanged();
|
||||
|
||||
// mSearchView.onDataSetChanged(); // TODO:
|
||||
|
||||
updateSpinnerState(getCursor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDataSetInvalidated() {
|
||||
if (DBG) Log.d(LOG_TAG, "notifyDataSetInvalidated");
|
||||
super.notifyDataSetInvalidated();
|
||||
|
||||
updateSpinnerState(getCursor());
|
||||
}
|
||||
|
||||
private void updateSpinnerState(Cursor cursor) {
|
||||
Bundle extras = cursor != null ? cursor.getExtras() : null;
|
||||
if (DBG) {
|
||||
Log.d(LOG_TAG, "updateSpinnerState - extra = "
|
||||
+ (extras != null
|
||||
? extras.getBoolean(SearchManager.CURSOR_EXTRA_KEY_IN_PROGRESS)
|
||||
: null));
|
||||
}
|
||||
// Check if the Cursor indicates that the query is not complete and show the spinner
|
||||
if (extras != null
|
||||
&& extras.getBoolean(SearchManager.CURSOR_EXTRA_KEY_IN_PROGRESS)) {
|
||||
// mSearchView.getWindow().getDecorView().post(mStartSpinnerRunnable); // TODO:
|
||||
return;
|
||||
}
|
||||
// If cursor is null or is done, stop the spinner
|
||||
// mSearchView.getWindow().getDecorView().post(mStopSpinnerRunnable); // TODO:
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache columns.
|
||||
*/
|
||||
@Override
|
||||
public void changeCursor(Cursor c) {
|
||||
if (DBG) Log.d(LOG_TAG, "changeCursor(" + c + ")");
|
||||
|
||||
if (mClosed) {
|
||||
Log.w(LOG_TAG, "Tried to change cursor after adapter was closed.");
|
||||
if (c != null) c.close();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
super.changeCursor(c);
|
||||
|
||||
if (c != null) {
|
||||
mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1);
|
||||
mText2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2);
|
||||
mText2UrlCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2_URL);
|
||||
mIconName1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1);
|
||||
mIconName2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2);
|
||||
mFlagsCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FLAGS);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "error changing cursor and caching columns", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags the view with cached child view look-ups.
|
||||
*/
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
View v = super.newView(context, cursor, parent);
|
||||
v.setTag(new ChildViewCache(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache of the child views of drop-drown list items, to avoid looking up the children
|
||||
* each time the contents of a list item are changed.
|
||||
*/
|
||||
private final static class ChildViewCache {
|
||||
public final TextView mText1;
|
||||
public final TextView mText2;
|
||||
public final ImageView mIcon1;
|
||||
public final ImageView mIcon2;
|
||||
public final ImageView mIconRefine;
|
||||
|
||||
public ChildViewCache(View v) {
|
||||
mText1 = (TextView) v.findViewById(android.R.id.text1);
|
||||
mText2 = (TextView) v.findViewById(android.R.id.text2);
|
||||
mIcon1 = (ImageView) v.findViewById(android.R.id.icon1);
|
||||
mIcon2 = (ImageView) v.findViewById(android.R.id.icon2);
|
||||
mIconRefine = (ImageView) v.findViewById(R.id.edit_query);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
ChildViewCache views = (ChildViewCache) view.getTag();
|
||||
|
||||
int flags = 0;
|
||||
if (mFlagsCol != INVALID_INDEX) {
|
||||
flags = cursor.getInt(mFlagsCol);
|
||||
}
|
||||
if (views.mText1 != null) {
|
||||
String text1 = getStringOrNull(cursor, mText1Col);
|
||||
setViewText(views.mText1, text1);
|
||||
}
|
||||
if (views.mText2 != null) {
|
||||
// First check TEXT_2_URL
|
||||
CharSequence text2 = getStringOrNull(cursor, mText2UrlCol);
|
||||
if (text2 != null) {
|
||||
text2 = formatUrl(text2);
|
||||
} else {
|
||||
text2 = getStringOrNull(cursor, mText2Col);
|
||||
}
|
||||
|
||||
// If no second line of text is indicated, allow the first line of text
|
||||
// to be up to two lines if it wants to be.
|
||||
if (TextUtils.isEmpty(text2)) {
|
||||
if (views.mText1 != null) {
|
||||
views.mText1.setSingleLine(false);
|
||||
views.mText1.setMaxLines(2);
|
||||
}
|
||||
} else {
|
||||
if (views.mText1 != null) {
|
||||
views.mText1.setSingleLine(true);
|
||||
views.mText1.setMaxLines(1);
|
||||
}
|
||||
}
|
||||
setViewText(views.mText2, text2);
|
||||
}
|
||||
|
||||
if (views.mIcon1 != null) {
|
||||
setViewDrawable(views.mIcon1, getIcon1(cursor), View.INVISIBLE);
|
||||
}
|
||||
if (views.mIcon2 != null) {
|
||||
setViewDrawable(views.mIcon2, getIcon2(cursor), View.GONE);
|
||||
}
|
||||
if (mQueryRefinement == REFINE_ALL
|
||||
|| (mQueryRefinement == REFINE_BY_ENTRY
|
||||
&& (flags & SearchManager.FLAG_QUERY_REFINEMENT) != 0)) {
|
||||
views.mIconRefine.setVisibility(View.VISIBLE);
|
||||
views.mIconRefine.setTag(views.mText1.getText());
|
||||
views.mIconRefine.setOnClickListener(this);
|
||||
} else {
|
||||
views.mIconRefine.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
Object tag = v.getTag();
|
||||
if (tag instanceof CharSequence) {
|
||||
mSearchView.onQueryRefine((CharSequence) tag);
|
||||
}
|
||||
}
|
||||
|
||||
private CharSequence formatUrl(CharSequence url) {
|
||||
if (mUrlColor == null) {
|
||||
// Lazily get the URL color from the current theme.
|
||||
TypedValue colorValue = new TypedValue();
|
||||
mContext.getTheme().resolveAttribute(R.attr.textColorSearchUrl, colorValue, true);
|
||||
mUrlColor = mContext.getResources().getColorStateList(colorValue.resourceId);
|
||||
}
|
||||
|
||||
SpannableString text = new SpannableString(url);
|
||||
text.setSpan(new TextAppearanceSpan(null, 0, 0, mUrlColor, null),
|
||||
0, url.length(),
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
return text;
|
||||
}
|
||||
|
||||
private void setViewText(TextView v, CharSequence text) {
|
||||
// Set the text even if it's null, since we need to clear any previous text.
|
||||
v.setText(text);
|
||||
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
v.setVisibility(View.GONE);
|
||||
} else {
|
||||
v.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private Drawable getIcon1(Cursor cursor) {
|
||||
if (mIconName1Col == INVALID_INDEX) {
|
||||
return null;
|
||||
}
|
||||
String value = cursor.getString(mIconName1Col);
|
||||
Drawable drawable = getDrawableFromResourceValue(value);
|
||||
if (drawable != null) {
|
||||
return drawable;
|
||||
}
|
||||
return getDefaultIcon1(cursor);
|
||||
}
|
||||
|
||||
private Drawable getIcon2(Cursor cursor) {
|
||||
if (mIconName2Col == INVALID_INDEX) {
|
||||
return null;
|
||||
}
|
||||
String value = cursor.getString(mIconName2Col);
|
||||
return getDrawableFromResourceValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the drawable in an image view, makes sure the view is only visible if there
|
||||
* is a drawable.
|
||||
*/
|
||||
private void setViewDrawable(ImageView v, Drawable drawable, int nullVisibility) {
|
||||
// Set the icon even if the drawable is null, since we need to clear any
|
||||
// previous icon.
|
||||
v.setImageDrawable(drawable);
|
||||
|
||||
if (drawable == null) {
|
||||
v.setVisibility(nullVisibility);
|
||||
} else {
|
||||
v.setVisibility(View.VISIBLE);
|
||||
|
||||
// This is a hack to get any animated drawables (like a 'working' spinner)
|
||||
// to animate. You have to setVisible true on an AnimationDrawable to get
|
||||
// it to start animating, but it must first have been false or else the
|
||||
// call to setVisible will be ineffective. We need to clear up the story
|
||||
// about animated drawables in the future, see http://b/1878430.
|
||||
drawable.setVisible(false, false);
|
||||
drawable.setVisible(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text to show in the query field when a suggestion is selected.
|
||||
*
|
||||
* @param cursor The Cursor to read the suggestion data from. The Cursor should already
|
||||
* be moved to the suggestion that is to be read from.
|
||||
* @return The text to show, or <code>null</code> if the query should not be
|
||||
* changed when selecting this suggestion.
|
||||
*/
|
||||
@Override
|
||||
public CharSequence convertToString(Cursor cursor) {
|
||||
if (cursor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String query = getColumnString(cursor, SearchManager.SUGGEST_COLUMN_QUERY);
|
||||
if (query != null) {
|
||||
return query;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is overridden purely to provide a bit of protection against
|
||||
* flaky content providers.
|
||||
*
|
||||
* @see android.widget.ListAdapter#getView(int, View, ViewGroup)
|
||||
*/
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
try {
|
||||
return super.getView(position, convertView, parent);
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(LOG_TAG, "Search suggestions cursor threw exception.", e);
|
||||
// Put exception string in item title
|
||||
View v = newView(mContext, mCursor, parent);
|
||||
if (v != null) {
|
||||
ChildViewCache views = (ChildViewCache) v.getTag();
|
||||
TextView tv = views.mText1;
|
||||
tv.setText(e.toString());
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a drawable given a value provided by a suggestion provider.
|
||||
*
|
||||
* This value could be just the string value of a resource id
|
||||
* (e.g., "2130837524"), in which case we will try to retrieve a drawable from
|
||||
* the provider's resources. If the value is not an integer, it is
|
||||
* treated as a Uri and opened with
|
||||
* {@link ContentResolver#openOutputStream(android.net.Uri, String)}.
|
||||
*
|
||||
* All resources and URIs are read using the suggestion provider's context.
|
||||
*
|
||||
* If the string is not formatted as expected, or no drawable can be found for
|
||||
* the provided value, this method returns null.
|
||||
*
|
||||
* @param drawableId a string like "2130837524",
|
||||
* "android.resource://com.android.alarmclock/2130837524",
|
||||
* or "content://contacts/photos/253".
|
||||
* @return a Drawable, or null if none found
|
||||
*/
|
||||
private Drawable getDrawableFromResourceValue(String drawableId) {
|
||||
if (drawableId == null || drawableId.length() == 0 || "0".equals(drawableId)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
// First, see if it's just an integer
|
||||
int resourceId = Integer.parseInt(drawableId);
|
||||
// It's an int, look for it in the cache
|
||||
String drawableUri = ContentResolver.SCHEME_ANDROID_RESOURCE
|
||||
+ "://" + mProviderContext.getPackageName() + "/" + resourceId;
|
||||
// Must use URI as cache key, since ints are app-specific
|
||||
Drawable drawable = checkIconCache(drawableUri);
|
||||
if (drawable != null) {
|
||||
return drawable;
|
||||
}
|
||||
// Not cached, find it by resource ID
|
||||
drawable = mProviderContext.getResources().getDrawable(resourceId);
|
||||
// Stick it in the cache, using the URI as key
|
||||
storeInIconCache(drawableUri, drawable);
|
||||
return drawable;
|
||||
} catch (NumberFormatException nfe) {
|
||||
// It's not an integer, use it as a URI
|
||||
Drawable drawable = checkIconCache(drawableId);
|
||||
if (drawable != null) {
|
||||
return drawable;
|
||||
}
|
||||
Uri uri = Uri.parse(drawableId);
|
||||
drawable = getDrawable(uri);
|
||||
storeInIconCache(drawableId, drawable);
|
||||
return drawable;
|
||||
} catch (Resources.NotFoundException nfe) {
|
||||
// It was an integer, but it couldn't be found, bail out
|
||||
Log.w(LOG_TAG, "Icon resource not found: " + drawableId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a drawable by URI, without using the cache.
|
||||
*
|
||||
* @return A drawable, or {@code null} if the drawable could not be loaded.
|
||||
*/
|
||||
private Drawable getDrawable(Uri uri) {
|
||||
try {
|
||||
String scheme = uri.getScheme();
|
||||
if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
|
||||
// Load drawables through Resources, to get the source density information
|
||||
try {
|
||||
return getTheDrawable(uri);
|
||||
} catch (Resources.NotFoundException ex) {
|
||||
throw new FileNotFoundException("Resource does not exist: " + uri);
|
||||
}
|
||||
} else {
|
||||
// Let the ContentResolver handle content and file URIs.
|
||||
InputStream stream = mProviderContext.getContentResolver().openInputStream(uri);
|
||||
if (stream == null) {
|
||||
throw new FileNotFoundException("Failed to open " + uri);
|
||||
}
|
||||
try {
|
||||
return Drawable.createFromStream(stream, null);
|
||||
} finally {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException ex) {
|
||||
Log.e(LOG_TAG, "Error closing icon stream for " + uri, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
Log.w(LOG_TAG, "Icon not found: " + uri + ", " + fnfe.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Drawable getTheDrawable(Uri uri) throws FileNotFoundException {
|
||||
String authority = uri.getAuthority();
|
||||
Resources r;
|
||||
if (TextUtils.isEmpty(authority)) {
|
||||
throw new FileNotFoundException("No authority: " + uri);
|
||||
} else {
|
||||
try {
|
||||
r = mContext.getPackageManager().getResourcesForApplication(authority);
|
||||
} catch (NameNotFoundException ex) {
|
||||
throw new FileNotFoundException("No package found for authority: " + uri);
|
||||
}
|
||||
}
|
||||
List<String> path = uri.getPathSegments();
|
||||
if (path == null) {
|
||||
throw new FileNotFoundException("No path: " + uri);
|
||||
}
|
||||
int len = path.size();
|
||||
int id;
|
||||
if (len == 1) {
|
||||
try {
|
||||
id = Integer.parseInt(path.get(0));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new FileNotFoundException("Single path segment is not a resource ID: " + uri);
|
||||
}
|
||||
} else if (len == 2) {
|
||||
id = r.getIdentifier(path.get(1), path.get(0), authority);
|
||||
} else {
|
||||
throw new FileNotFoundException("More than two path segments: " + uri);
|
||||
}
|
||||
if (id == 0) {
|
||||
throw new FileNotFoundException("No resource found for: " + uri);
|
||||
}
|
||||
return r.getDrawable(id);
|
||||
}
|
||||
|
||||
private Drawable checkIconCache(String resourceUri) {
|
||||
Drawable.ConstantState cached = mOutsideDrawablesCache.get(resourceUri);
|
||||
if (cached == null) {
|
||||
return null;
|
||||
}
|
||||
if (DBG) Log.d(LOG_TAG, "Found icon in cache: " + resourceUri);
|
||||
return cached.newDrawable();
|
||||
}
|
||||
|
||||
private void storeInIconCache(String resourceUri, Drawable drawable) {
|
||||
if (drawable != null) {
|
||||
mOutsideDrawablesCache.put(resourceUri, drawable.getConstantState());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the left-hand side icon that will be used for the current suggestion
|
||||
* if the suggestion contains an icon column but no icon or a broken icon.
|
||||
*
|
||||
* @param cursor A cursor positioned at the current suggestion.
|
||||
* @return A non-null drawable.
|
||||
*/
|
||||
private Drawable getDefaultIcon1(Cursor cursor) {
|
||||
// Fall back to a default icon
|
||||
return mContext.getPackageManager().getDefaultActivityIcon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the activity or application icon for an activity.
|
||||
* Uses the local icon cache for fast repeated lookups.
|
||||
*
|
||||
* @param component Name of an activity.
|
||||
* @return A drawable, or {@code null} if neither the activity nor the application
|
||||
* has an icon set.
|
||||
*/
|
||||
private Drawable getActivityIconWithCache(ComponentName component) {
|
||||
// First check the icon cache
|
||||
String componentIconKey = component.flattenToShortString();
|
||||
// Using containsKey() since we also store null values.
|
||||
if (mOutsideDrawablesCache.containsKey(componentIconKey)) {
|
||||
Drawable.ConstantState cached = mOutsideDrawablesCache.get(componentIconKey);
|
||||
return cached == null ? null : cached.newDrawable(mProviderContext.getResources());
|
||||
}
|
||||
// Then try the activity or application icon
|
||||
Drawable drawable = getActivityIcon(component);
|
||||
// Stick it in the cache so we don't do this lookup again.
|
||||
Drawable.ConstantState toCache = drawable == null ? null : drawable.getConstantState();
|
||||
mOutsideDrawablesCache.put(componentIconKey, toCache);
|
||||
return drawable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the activity or application icon for an activity.
|
||||
*
|
||||
* @param component Name of an activity.
|
||||
* @return A drawable, or {@code null} if neither the acitivy or the application
|
||||
* have an icon set.
|
||||
*/
|
||||
private Drawable getActivityIcon(ComponentName component) {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
final ActivityInfo activityInfo;
|
||||
try {
|
||||
activityInfo = pm.getActivityInfo(component, PackageManager.GET_META_DATA);
|
||||
} catch (NameNotFoundException ex) {
|
||||
Log.w(LOG_TAG, ex.toString());
|
||||
return null;
|
||||
}
|
||||
int iconId = activityInfo.getIconResource();
|
||||
if (iconId == 0) return null;
|
||||
String pkg = component.getPackageName();
|
||||
Drawable drawable = pm.getDrawable(pkg, iconId, activityInfo.applicationInfo);
|
||||
if (drawable == null) {
|
||||
Log.w(LOG_TAG, "Invalid icon resource " + iconId + " for "
|
||||
+ component.flattenToShortString());
|
||||
return null;
|
||||
}
|
||||
return drawable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a string column by name.
|
||||
*
|
||||
* @param cursor Cursor to read the value from.
|
||||
* @param columnName The name of the column to read.
|
||||
* @return The value of the given column, or <code>null</null>
|
||||
* if the cursor does not contain the given column.
|
||||
*/
|
||||
public static String getColumnString(Cursor cursor, String columnName) {
|
||||
int col = cursor.getColumnIndex(columnName);
|
||||
return getStringOrNull(cursor, col);
|
||||
}
|
||||
|
||||
private static String getStringOrNull(Cursor cursor, int col) {
|
||||
if (col == INVALID_INDEX) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return cursor.getString(col);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG,
|
||||
"unexpected error retrieving valid column from cursor, "
|
||||
+ "did the remote process die?", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="false" android:color="@color/abs__bright_foreground_disabled_holo_dark"/>
|
||||
<item android:color="@color/abs__bright_foreground_holo_dark"/> <!-- not selected -->
|
||||
</selector>
|
@ -1,21 +0,0 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="false" android:color="@color/abs__bright_foreground_disabled_holo_light"/>
|
||||
<item android:color="@color/abs__bright_foreground_holo_light"/> <!-- not selected -->
|
||||
</selector>
|
||||
|
@ -1,24 +0,0 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="false" android:color="@color/abs__bright_foreground_disabled_holo_dark"/>
|
||||
<item android:state_window_focused="false" android:color="@color/abs__bright_foreground_holo_dark"/>
|
||||
<item android:state_pressed="true" android:color="@color/abs__bright_foreground_holo_dark"/>
|
||||
<item android:state_selected="true" android:color="@color/abs__bright_foreground_holo_dark"/>
|
||||
<item android:state_activated="true" android:color="@color/abs__bright_foreground_holo_dark"/>
|
||||
<item android:color="@color/abs__bright_foreground_holo_dark"/> <!-- not selected -->
|
||||
</selector>
|
@ -1,26 +0,0 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="false" android:color="@color/abs__bright_foreground_disabled_holo_light"/>
|
||||
<item android:state_window_focused="false" android:color="@color/abs__bright_foreground_holo_light"/>
|
||||
<item android:state_pressed="true" android:color="@color/abs__bright_foreground_holo_light"/>
|
||||
<item android:state_selected="true" android:color="@color/abs__bright_foreground_holo_light"/>
|
||||
<item android:state_activated="true" android:color="@color/abs__bright_foreground_holo_light"/>
|
||||
<item android:color="@color/abs__bright_foreground_holo_light"/> <!-- not selected -->
|
||||
|
||||
</selector>
|
||||
|
Before Width: | Height: | Size: 144 B |
Before Width: | Height: | Size: 138 B |
Before Width: | Height: | Size: 144 B |
Before Width: | Height: | Size: 135 B |
Before Width: | Height: | Size: 134 B |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 146 B |
Before Width: | Height: | Size: 145 B |